Files
pydantic/benchmarks/test_cattrs.py
T
2019-11-08 17:41:12 +00:00

102 lines
3.4 KiB
Python

from datetime import datetime
from typing import List, Optional
import attr
import cattr
from dateutil.parser import parse
class TestCAttrs:
package = 'attrs + cattrs'
version = attr.__version__
def __init__(self, allow_extra):
# cf. https://github.com/Tinche/cattrs/issues/26 why at least structure_str is needed
def structure_str(s, _):
if not isinstance(s, str):
raise ValueError()
return s
def structure_int(i, _):
if not isinstance(i, int):
raise ValueError()
return i
class PositiveInt(int):
...
def structure_posint(i, x):
i = PositiveInt(i)
if not isinstance(i, PositiveInt):
raise ValueError()
if i <= 0:
raise ValueError()
return i
cattr.register_structure_hook(datetime, lambda isostring, _: parse(isostring))
cattr.register_structure_hook(str, structure_str)
cattr.register_structure_hook(int, structure_int)
cattr.register_structure_hook(PositiveInt, structure_posint)
def str_len_val(max_len: int, min_len: int = 0, required: bool = False):
# validate the max len of a string and optionally its min len and whether None is
# an acceptable value
def _check_str_len(self, attribute, value):
if value is None:
if required:
raise ValueError("")
else:
return
if len(value) > max_len:
raise ValueError("")
if min_len and len(value) < min_len:
raise ValueError("")
return _check_str_len
def pos_int(self, attribute, value):
# Validate that value is a positive >0 integer; None is allowed
if value is None:
return
if value <= 0:
raise ValueError("")
@attr.s(auto_attribs=True, frozen=True, kw_only=True)
class Skill:
subject: str
subject_id: int
category: str
qual_level: str
qual_level_id: int
qual_level_ranking: float = 0
@attr.s(auto_attribs=True, frozen=True, kw_only=True)
class Location:
latitude: float = None
longitude: float = None
@attr.s(auto_attribs=True, frozen=True, kw_only=True)
class Model:
id: int
sort_index: float
client_name: str = attr.ib(validator=str_len_val(255))
# client_email: EmailStr = None
client_phone: Optional[str] = attr.ib(default=None, validator=str_len_val(255))
location: Optional[Location] = None
contractor: Optional[PositiveInt]
upstream_http_referrer: Optional[str] = attr.ib(default=None, validator=str_len_val(1023))
grecaptcha_response: str = attr.ib(validator=str_len_val(1000, 20, required=True))
last_updated: Optional[datetime] = None
skills: List[Skill] = []
self.model = Model
def validate(self, data):
try:
return True, cattr.structure(data, self.model)
except ValueError as e:
return False, str(e)
except TypeError as e:
return False, str(e)