Skip to content

Instantly share code, notes, and snippets.

@rochacbruno
Created September 30, 2021 11:13
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save rochacbruno/978405e4839142e409f8402eece505e8 to your computer and use it in GitHub Desktop.
Save rochacbruno/978405e4839142e409f8402eece505e8 to your computer and use it in GitHub Desktop.
Validate Dataclass Python
from typing import Union, List
from dataclasses import dataclass
class Validations:
def __post_init__(self):
"""Run validation methods if declared.
The validation method can be a simple check
that raises ValueError or a transformation to
the field value.
The validation is performed by calling a function named:
`validate_<field_name>(self, value, field) -> field.type`
"""
for name, field in self.__dataclass_fields__.items():
if (method := getattr(self, f"validate_{name}", None)):
setattr(self, name, method(getattr(self, name), field=field))
@dataclass
class Product(Validations):
name: str
tags: Union[str, List[str]]
def validate_name(self, value, **_) -> str:
if len(value) < 3 or len(value) > 20:
raise ValueError("name must have between 3 and 20 chars.")
return value
def validate_tags(self, value, **_) -> List[str]:
"""Ensure tags are always List[str] even if "tag1,tag2" is passed"""
if isinstance(value, str):
value = [v.strip() for v in value.split(",")]
return value
if __name__ == "__main__":
product = Product(name="product", tags="tag1, tag2")
assert product.tags == ["tag1", "tag2"] # transformed to List[str]
try:
product = Product(name="pr", tags="tag1, tag2, tag3")
except ValueError as e:
assert str(e) == "name must have between 3 and 20 chars."
@EnriqueSoria
Copy link

@bmccutchon
Copy link

This won't validate changes to the field values after initialization.

@rochacbruno
Copy link
Author

@bmccutchon to validate assignments after initialization we would need to use descriptors.

@boddah-182
Copy link

Hello, @rochacbruno. Looks great. But why we're passing 'field' to validation methods? Is it for methods which may require extra data defined in field?

@mikybars
Copy link

mikybars commented Feb 3, 2023

Clever solution @rochacbruno! I've reworked it a little bit to make it work with setters also:

https://gist.github.com/almibarss/07397a021314a5020d0f7e2708eb175e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment