class Model(BaseModel): short_bytes: conbytes(min_length=2, max_length=10) strip_bytes: conbytes(strip_whitespace=True) short_str: constr(min_length=2, max_length=10) regex_str: constr(regex='apple (pie|tart|sandwich)') strip_str: constr(strip_whitespace=True) big_int: conint(gt=1000, lt=1024) mod_int: conint(multiple_of=5) pos_int: PositiveInt neg_int: NegativeInt big_float: confloat(gt=1000, lt=1024) unit_interval: confloat(ge=0, le=1) mod_float: confloat(multiple_of=0.5) pos_float: PositiveFloat neg_float: NegativeFloat short_list: conlist(int, min_items=1, max_items=4) decimal_positive: condecimal(gt=0) decimal_negative: condecimal(lt=0) decimal_max_digits_and_places: condecimal(max_digits=2, decimal_places=2) mod_decimal: condecimal(multiple_of=Decimal('0.25'))
class Model(BaseModel): cos_function: PyObject = None path_to_something: Path = None path_to_file: FilePath = None path_to_directory: DirectoryPath = None short_bytes: conbytes(min_length=2, max_length=10) = None strip_bytes: conbytes(strip_whitespace=True) short_str: constr(min_length=2, max_length=10) = None regex_str: constr(regex='apple (pie|tart|sandwich)') = None strip_str: constr(strip_whitespace=True) big_int: conint(gt=1000, lt=1024) = None mod_int: conint(multiple_of=5) = None pos_int: PositiveInt = None neg_int: NegativeInt = None big_float: confloat(gt=1000, lt=1024) = None unit_interval: confloat(ge=0, le=1) = None mod_float: confloat(multiple_of=0.5) = None pos_float: PositiveFloat = None neg_float: NegativeFloat = None email_address: EmailStr = None email_and_name: NameEmail = None url: UrlStr = None password: SecretStr = None password_bytes: SecretBytes = None db_name = 'foobar' db_user = '******' db_password: str = None db_host = 'localhost' db_port = '5432' db_driver = 'postgres' db_query: dict = None dsn: DSN = None decimal: Decimal = None decimal_positive: condecimal(gt=0) = None decimal_negative: condecimal(lt=0) = None decimal_max_digits_and_places: condecimal(max_digits=2, decimal_places=2) = None mod_decimal: condecimal(multiple_of=Decimal('0.25')) = None uuid_any: UUID = None uuid_v1: UUID1 = None uuid_v3: UUID3 = None uuid_v4: UUID4 = None uuid_v5: UUID5 = None ipvany: IPvAnyAddress = None ipv4: IPv4Address = None ipv6: IPv6Address = None ip_vany_network: IPvAnyNetwork = None ip_v4_network: IPv4Network = None ip_v6_network: IPv6Network = None ip_vany_interface: IPvAnyInterface = None ip_v4_interface: IPv4Interface = None ip_v6_interface: IPv6Interface = None
def test_pydantic_conbytes_field(self, normalize_sdl): value = pydantic2graphene.to_graphene( to_pydantic_class(pydantic.conbytes())) expected_value = """ type FakeGql { field: String! } """ assert normalize_sdl(value) == normalize_sdl(expected_value)
class User(BaseModel): name: Optional[str] = Field(None, example='ken') age: Optional[int] = None salary: Optional[conint(ge=0)] = None debt: Optional[conint(le=0)] = None loan: Optional[confloat(le=0.0)] = None tel: Optional[constr(regex=r'^(\([0-9]{3}\))?[0-9]{3}-[0-9]{4}$')] = None height: Optional[confloat(ge=0.0)] = None weight: Optional[confloat(ge=0.0)] = None active: Optional[bool] = None photo: Optional[conbytes(min_length=100)] = None
class ConstrainedBytesWithRegex(pydantic.conbytes(**kwargs)): @classmethod def __get_validators__(cls): yield from super().__get_validators__() yield cls.match_regex @classmethod def match_regex(cls, value: bytes) -> bytes: if compiled_regex is not None and compiled_regex.match( value) is None: raise ValueError( f"Value `{value}` doesn't match regex `{regex}`") return value
class ConBytesModel(BaseModel): v: conbytes(max_length=10) = b'foobar'
class VenueBannerContentModel(BaseModel): content: pydantic.conbytes( min_length=2, max_length=VENUE_BANNER_MAX_SIZE) # type: ignore content_type: pydantic.constr(strip_whitespace=True, to_lower=True, max_length=16) # type: ignore file_name: pydantic.constr(strip_whitespace=True, to_lower=True, min_length=5, max_length=256) # type: ignore class Config: extra = pydantic.Extra.forbid anystr_strip_whitespace = True @root_validator(pre=True) @classmethod def validate_banner(cls, values: dict) -> dict: """ Validate content (is not an invalid image) using PIL + set and validate content type using image build from previous step """ try: image = Image.open(BytesIO(values["content"])) except Exception: raise ValueError("Format de l'image invalide") legit_image_types = {"jpg", "jpeg", "png"} values["content_type"] = image.format.lower() if not values["content_type"] in legit_image_types: raise ValueError("Format de l'image invalide") return values @classmethod def from_request(cls, request: typing.Any) -> "VenueBannerContentModel": cls.validate_request(request) file = request.files["banner"] return VenueBannerContentModel( content=file.read(VENUE_BANNER_MAX_SIZE), file_name=file.filename, ) @classmethod def validate_request(cls, request: typing.Any) -> typing.Any: """ If the request has a content_lenght information, use directly to avoid reading the whole content to check its size. If not, do not consider this a an error: it will be checked later. """ try: file = request.files["banner"] except (AttributeError, KeyError): raise ValueError("Image manquante") if file.content_length and file.content_length > VENUE_BANNER_MAX_SIZE: raise ValueError( f"Image trop grande, max: {VENUE_BANNER_MAX_SIZE / 1_000}Ko") return request