smarie / python-pyfields

Define fields in python classes. Easily.
https://smarie.github.io/python-pyfields
BSD 3-Clause "New" or "Revised" License
45 stars 10 forks source link

Provide an auto-fields feature like attrs/pydantic for python 3.6+ #55

Closed smarie closed 4 years ago

smarie commented 4 years ago

the idea came from implementing pydantic's benchmark today (by the way, early results show that cythonized version of pyfields is better than pydantic and non-cythonized is equivalent).

It ended up being quite heavy to implement the model's benchmark:

class Model:
        __init__ = make_init()
        id: int = field(check_type=True)
        client_name: str = field(check_type=True,
                                 validators={'max length is 255': lambda s: len(s) <= 255})   # constr(max_length=255)
        sort_index: float = field(check_type=True)
        # client_email: EmailStr = None
        client_phone: str = field(check_type=True, default=None,
                                  validators={'max length is 255': lambda s: len(s) <= 255})  # constr(max_length=255)

        class Location:
            __init__ = make_init()
            latitude: float = field(check_type=True, default=None)
            longitude: float = field(check_type=True, default=None)

        location: Location = field(check_type=True, default=None, converters={dict: lambda d: Model.Location(**d)})

        contractor: int = field(check_type=True, default=None,
                                converters={str: lambda s: int(s)},
                                validators={'positive int': lambda x: x >= 0})  # PositiveInt
        upstream_http_referrer: str = field(check_type=True, default=None,
                                            validators={'max length is 1023': lambda s: len(s) <= 1023})  # constr(max_length=1023)
        grecaptcha_response: str = field(check_type=True,
                                         validators={'length should be between 20 and 1000': lambda s: 20 <= len(s) <= 1000})  # constr(min_length=20, max_length=1000)
        last_updated: datetime = field(check_type=True, default=None,
                                       converters={str: lambda isostring: parse_datetime_iso(isostring)})

        class Skill:
            __init__ = make_init()
            subject: str = field(check_type=True, )
            subject_id: int = field(check_type=True, )
            category: str = field(check_type=True, )
            qual_level: str = field(check_type=True, )
            qual_level_id: int = field(check_type=True, )
            qual_level_ranking: float = field(check_type=True, default=0)

        skills: List[Skill] = field(check_type=True, default_factory=copy_value([]),
                                    converters={Iterable: lambda l: [Model.Skill(**o) if isinstance(o, dict) else o for o in l]})

    self.model = Model

This could be simplified by a few things: