Validate Dataclass Fields in __post_init__
Enforce types and ranges on dataclass fields at construction time, normalize values, and raise one error listing every invalid field.
Code
from dataclasses import dataclass
class ValidationError(ValueError):
def __init__(self, errors: dict[str, str]) -> None:
self.errors = errors
message = "; ".join(f"{field}: {text}" for field, text in errors.items())
super().__init__(message)
@dataclass
class Signup:
email: str
age: int
username: str
def __post_init__(self) -> None:
errors: dict[str, str] = {}
email = self.email.strip().lower()
if email.count("@") != 1 or email.startswith("@") or email.endswith("@"):
errors["email"] = "must contain one @ with local and domain parts"
else:
self.email = email
if isinstance(self.age, bool) or not isinstance(self.age, int):
errors["age"] = "must be an integer"
elif not 13 <= self.age <= 120:
errors["age"] = "must be between 13 and 120"
username = self.username.strip()
if not 3 <= len(username) <= 20:
errors["username"] = "must be 3-20 characters"
elif not username.replace("_", "").isalnum():
errors["username"] = "may contain only letters, digits, and underscores"
else:
self.username = username
if errors:
raise ValidationError(errors)
def main() -> None:
print(Signup(email=" [email protected] ", age=36, username=" ada_1 "))
try:
Signup(email="nope", age=True, username="x")
except ValidationError as error:
print(error)
print(error.errors)
if __name__ == "__main__":
main()
Report a problem with this exampleOpens a pre-filled issue on GitHub.