mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
594effa279
* working on core schema generation * adapting main.py * getting tests to run * fix tests * disable pyright, fix mypy * moving to class-based model generation * working on validators * change how models are created * start fixing test_main.py * fixing mypy * SelfType * recursive models working, more tests fixed * fix tests on <3.10 * get docs build to pass * starting to cleanup types.py * starting works on custom types * working on using annotated-types * using annoated types for constraints * lots of cleanup, fixing network tests * network tests passing 🎉 * working on types * working on types and cleanup * fixing UUID type, restructing again * more types and newer pydantic-core * working on Iterable * more test_types tests * support newer pydantic-core, fixing more test_types.py * working through more test_types.py * test_types.py at last passing locally 🎉 * fixing more tests in test_types.py * fix datetime_parse tests and linting * get tests running again, rename to test_datetime.py * renaming internal modules * working through mypy errors * fixing mypy * refactoring _generate_schema.py * test_main.py passing * uprev deps * fix conftest and linting? * importing Annotated * ltining * import Annotated from typing_extensions * fixing 3.7 compatibility * fixing tests on 3.9 * fix linting * fixing SecretField and 3.9 tests * customising get_type_hints * ignore warnings on 3.11 * spliting repr out of utils * removing unused bits of _repr, fix tests for 3.7 * more cleanup, removing many type aliases * clean up repr * support namedtuples and typeddicts * test is_union * removing errors, uprev pydantic-core * fix tests on 3.8 * fixing private attributes and model_post_init * renaming and cleanup * remove unnecessary PydanticMetadata inheritance * fixing forward refs and mypy tests * fix signatures, change how xfail works * revert mypy tests to 3.7 syntax * correct model title * try to fix tests * fixing ClassVar forward refs * uprev pydantic-core, new error format * add "force" argument to model_rebuild * Apply suggestions from code review Suggestions from @tiangolo and @hramezani 🙏 Co-authored-by: Hasan Ramezani <hasan.r67@gmail.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com> * more suggestions from @tiangolo * extra -> json_schema_extra on Field Co-authored-by: Hasan Ramezani <hasan.r67@gmail.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
131 lines
4.4 KiB
Python
131 lines
4.4 KiB
Python
import typing
|
|
from datetime import date
|
|
|
|
import pytest
|
|
|
|
import pydantic
|
|
from pydantic.networks import import_email_validator
|
|
|
|
try:
|
|
from hypothesis import HealthCheck, given, settings, strategies as st
|
|
except ImportError:
|
|
from unittest import mock
|
|
|
|
given = settings = lambda *a, **kw: (lambda f: f) # pass-through decorator
|
|
HealthCheck = st = mock.Mock()
|
|
|
|
pytestmark = pytest.mark.skipif(True, reason='"hypothesis" not installed')
|
|
|
|
|
|
def gen_models():
|
|
# TODO fix and remove this return
|
|
return
|
|
|
|
class MiscModel(pydantic.BaseModel):
|
|
# Each of these models contains a few related fields; the idea is that
|
|
# if there's a bug we have neither too many fields to dig through nor
|
|
# too many models to read.
|
|
color: pydantic.color.Color
|
|
json_any: pydantic.Json
|
|
|
|
class StringsModel(pydantic.BaseModel):
|
|
card: pydantic.PaymentCardNumber
|
|
secbytes: pydantic.SecretBytes
|
|
secstr: pydantic.SecretStr
|
|
|
|
class UUIDsModel(pydantic.BaseModel):
|
|
uuid1: pydantic.UUID1
|
|
uuid3: pydantic.UUID3
|
|
uuid4: pydantic.UUID4
|
|
uuid5: pydantic.UUID5
|
|
|
|
class IPvAnyAddress(pydantic.BaseModel):
|
|
address: pydantic.IPvAnyAddress
|
|
|
|
class IPvAnyInterface(pydantic.BaseModel):
|
|
interface: pydantic.IPvAnyInterface
|
|
|
|
class IPvAnyNetwork(pydantic.BaseModel):
|
|
network: pydantic.IPvAnyNetwork
|
|
|
|
class StrictNumbersModel(pydantic.BaseModel):
|
|
strictbool: pydantic.StrictBool
|
|
strictint: pydantic.StrictInt
|
|
strictfloat: pydantic.StrictFloat
|
|
strictstr: pydantic.StrictStr
|
|
|
|
class NumbersModel(pydantic.BaseModel):
|
|
posint: pydantic.PositiveInt
|
|
negint: pydantic.NegativeInt
|
|
posfloat: pydantic.PositiveFloat
|
|
negfloat: pydantic.NegativeFloat
|
|
nonposint: pydantic.NonPositiveInt
|
|
nonnegint: pydantic.NonNegativeInt
|
|
nonposfloat: pydantic.NonPositiveFloat
|
|
nonnegfloat: pydantic.NonNegativeFloat
|
|
|
|
class JsonModel(pydantic.BaseModel):
|
|
json_int: pydantic.Json[int]
|
|
json_float: pydantic.Json[float]
|
|
json_str: pydantic.Json[str]
|
|
json_int_or_str: pydantic.Json[typing.Union[int, str]]
|
|
json_list_of_float: pydantic.Json[typing.List[float]]
|
|
json_pydantic_model: pydantic.Json[pydantic.BaseModel]
|
|
|
|
class ConstrainedNumbersModel(pydantic.BaseModel):
|
|
conintt: pydantic.conint(gt=10, lt=100)
|
|
coninte: pydantic.conint(ge=10, le=100)
|
|
conintmul: pydantic.conint(ge=10, le=100, multiple_of=7)
|
|
confloatt: pydantic.confloat(gt=10, lt=100)
|
|
confloate: pydantic.confloat(ge=10, le=100)
|
|
confloatemul: pydantic.confloat(ge=10, le=100, multiple_of=4.2)
|
|
confloattmul: pydantic.confloat(gt=10, lt=100, multiple_of=10)
|
|
condecimalt: pydantic.condecimal(gt=10, lt=100)
|
|
condecimale: pydantic.condecimal(ge=10, le=100)
|
|
condecimaltplc: pydantic.condecimal(gt=10, lt=100, decimal_places=5)
|
|
condecimaleplc: pydantic.condecimal(ge=10, le=100, decimal_places=2)
|
|
|
|
class ConstrainedDateModel(pydantic.BaseModel):
|
|
condatet: pydantic.condate(gt=date(1980, 1, 1), lt=date(2180, 12, 31))
|
|
condatee: pydantic.condate(ge=date(1980, 1, 1), le=date(2180, 12, 31))
|
|
|
|
yield from (
|
|
MiscModel,
|
|
StringsModel,
|
|
UUIDsModel,
|
|
IPvAnyAddress,
|
|
IPvAnyInterface,
|
|
IPvAnyNetwork,
|
|
StrictNumbersModel,
|
|
NumbersModel,
|
|
JsonModel,
|
|
ConstrainedNumbersModel,
|
|
ConstrainedDateModel,
|
|
)
|
|
|
|
try:
|
|
import_email_validator()
|
|
except ImportError:
|
|
pass
|
|
else:
|
|
|
|
class EmailsModel(pydantic.BaseModel):
|
|
email: pydantic.EmailStr
|
|
name_email: pydantic.NameEmail
|
|
|
|
yield EmailsModel
|
|
|
|
|
|
@pytest.mark.parametrize('model', gen_models())
|
|
@settings(suppress_health_check={HealthCheck.too_slow}, deadline=None)
|
|
@given(data=st.data())
|
|
def test_can_construct_models_with_all_fields(data, model):
|
|
# The value of this test is to confirm that Hypothesis knows how to provide
|
|
# valid values for each field - otherwise, this would raise ValidationError.
|
|
instance = data.draw(st.from_type(model))
|
|
|
|
# We additionally check that the instance really is of type `model`, because
|
|
# an evil implementation could avoid ValidationError by means of e.g.
|
|
# `st.register_type_strategy(model, st.none())`, skipping the constructor.
|
|
assert isinstance(instance, model)
|