Skip to content

Commit

Permalink
feat: convert all empty strings to None before validation
Browse files Browse the repository at this point in the history
  • Loading branch information
waza-ari committed Jan 6, 2024
1 parent 71f4fab commit e5bc8ca
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 24 deletions.
13 changes: 2 additions & 11 deletions easyverein/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@
import json
from typing import Annotated

from pydantic import BeforeValidator, EmailStr, Field, PlainSerializer, UrlConstraints
from pydantic import Field, PlainSerializer, UrlConstraints
from pydantic_core import Url

from .validators import empty_string_to_none, parse_json_string

AnyHttpURL = Annotated[
Url,
UrlConstraints(allowed_schemes=["http", "https"]),
PlainSerializer(lambda x: str(x), return_type=str),
]
EasyVereinReference = Annotated[
int | AnyHttpURL | None, BeforeValidator(empty_string_to_none)
]
EasyVereinReference = int | AnyHttpURL | None
PositiveIntWithZero = Annotated[int, Field(ge=0)]
Date = Annotated[
datetime.date, PlainSerializer(lambda x: x.strftime("%Y-%m-%d"), return_type=str)
Expand All @@ -29,13 +25,8 @@
OptionsField = Annotated[
list[str] | None,
PlainSerializer(lambda x: json.dumps(x), return_type=str),
BeforeValidator(parse_json_string),
BeforeValidator(empty_string_to_none),
]
HexColor = Annotated[
str | None,
Field(min_length=7, max_length=7),
BeforeValidator(empty_string_to_none),
]

Email = Annotated[EmailStr | None, BeforeValidator(empty_string_to_none)]
6 changes: 0 additions & 6 deletions easyverein/core/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
from typing import Any


def empty_string_to_none(v: Any) -> Any:
if isinstance(v, str) and v == "":
return None
return v


def parse_json_string(v: Any) -> Any:
if isinstance(v, str):
return json.loads(v)
Expand Down
5 changes: 3 additions & 2 deletions easyverein/models/base.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from pydantic import BaseModel, Field, PositiveInt
from pydantic import Field, PositiveInt

from .mixins.empty_strings_mixin import EmptyStringsToNone
from ..core.types import DateTime, EasyVereinReference


class EasyVereinBase(BaseModel):
class EasyVereinBase(EmptyStringsToNone):
"""
Base class encapsulating common fields for all models
"""
Expand Down
10 changes: 5 additions & 5 deletions easyverein/models/contact_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

from typing import Any, Literal

from pydantic import Field
from pydantic import Field, EmailStr

from ..core.types import Date, Email
from .base import EasyVereinBase
from .mixins.required_attributes import required_mixin
from ..core.types import Date


class ContactDetails(EasyVereinBase):
Expand All @@ -31,9 +31,9 @@ class ContactDetails(EasyVereinBase):
nameAffix: str | None = Field(default=None, max_length=100)
dateOfBirth: Date | None = None
internalNote: str | None = None
privateEmail: Email | None = None
companyEmail: Email | None = None
companyEmailInvoice: Email | None = None
privateEmail: EmailStr | None = None
companyEmail: EmailStr | None = None
companyEmailInvoice: EmailStr | None = None
primaryEmail: str | None = "email"
preferredEmailField: Literal[0, 1, 2] | None = Field(
default=None, alias="_preferredEmailField"
Expand Down
24 changes: 24 additions & 0 deletions easyverein/models/mixins/empty_strings_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""
This module contains a generic plugin for Pydantic models that removes
empty strings and converts them to None.
"""
from typing import Any

from pydantic import BaseModel, model_validator


class EmptyStringsToNone(BaseModel):
"""
Mixin class for Pydantic models
"""

@model_validator(mode="before")
def empty_string_to_none(cls, data: Any) -> Any:
"""
Pydantic model validator, converting empty strings to None
"""
if isinstance(data, dict):
for k, v in data.items():
if isinstance(v, str) and v == "":
data[k] = None
return data

0 comments on commit e5bc8ca

Please sign in to comment.