1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
import pickle
import re
from datetime import datetime, timedelta, timezone
import pytest
from pydantic_core import core_schema
from pydantic_core._pydantic_core import SchemaValidator, ValidationError
def test_basic_schema_validator():
v = SchemaValidator(
{'type': 'dict', 'strict': True, 'keys_schema': {'type': 'int'}, 'values_schema': {'type': 'int'}}
)
v = pickle.loads(pickle.dumps(v))
assert v.validate_python({'1': 2, '3': 4}) == {1: 2, 3: 4}
assert v.validate_python({}) == {}
with pytest.raises(ValidationError, match=re.escape('[type=dict_type, input_value=[], input_type=list]')):
v.validate_python([])
def test_schema_validator_containing_config():
"""
Verify that the config object is not lost during (de)serialization.
"""
v = SchemaValidator(
core_schema.model_fields_schema({'f': core_schema.model_field(core_schema.str_schema())}),
config=core_schema.CoreConfig(extra_fields_behavior='allow'),
)
v = pickle.loads(pickle.dumps(v))
m, model_extra, fields_set = v.validate_python({'f': 'x', 'extra_field': '123'})
assert m == {'f': 'x'}
# If the config was lost during (de)serialization, the below checks would fail as
# the default behavior is to ignore extra fields.
assert model_extra == {'extra_field': '123'}
assert fields_set == {'f', 'extra_field'}
v.validate_assignment(m, 'f', 'y')
assert m == {'f': 'y'}
def test_schema_validator_tz_pickle() -> None:
"""
https://github.com/pydantic/pydantic-core/issues/589
"""
v = SchemaValidator(core_schema.datetime_schema())
original = datetime(2022, 6, 8, 12, 13, 14, tzinfo=timezone(timedelta(hours=-12, minutes=-15)))
validated = v.validate_python('2022-06-08T12:13:14-12:15')
assert validated == original
assert pickle.loads(pickle.dumps(validated)) == validated == original
# Should be defined at the module level for pickling to work:
class Model:
__pydantic_validator__: SchemaValidator
__pydantic_complete__ = True
def test_schema_validator_not_reused_when_unpickling() -> None:
s = SchemaValidator(
core_schema.model_schema(
cls=Model,
schema=core_schema.model_fields_schema(fields={}, model_name='Model'),
config={'title': 'Model'},
ref='Model:123',
)
)
Model.__pydantic_validator__ = s
assert 'Prebuilt' not in str(Model.__pydantic_validator__)
reconstructed = pickle.loads(pickle.dumps(Model.__pydantic_validator__))
assert 'Prebuilt' not in str(reconstructed)
|