-
Notifications
You must be signed in to change notification settings - Fork 259
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
SchemaSerializer.__reduce__
method to enable pickle
serializa…
…tion (#1006) Signed-off-by: Edward Oakes <ed.nmi.oakes@gmail.com>
- Loading branch information
Showing
7 changed files
with
158 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import json | ||
import pickle | ||
from datetime import timedelta | ||
|
||
import pytest | ||
|
||
from pydantic_core import core_schema | ||
from pydantic_core._pydantic_core import SchemaSerializer | ||
|
||
|
||
def repr_function(value, _info): | ||
return repr(value) | ||
|
||
|
||
def test_basic_schema_serializer(): | ||
s = SchemaSerializer(core_schema.dict_schema()) | ||
s = pickle.loads(pickle.dumps(s)) | ||
assert s.to_python({'a': 1, b'b': 2, 33: 3}) == {'a': 1, b'b': 2, 33: 3} | ||
assert s.to_python({'a': 1, b'b': 2, 33: 3, True: 4}, mode='json') == {'a': 1, 'b': 2, '33': 3, 'true': 4} | ||
assert s.to_json({'a': 1, b'b': 2, 33: 3, True: 4}) == b'{"a":1,"b":2,"33":3,"true":4}' | ||
|
||
assert s.to_python({(1, 2): 3}) == {(1, 2): 3} | ||
assert s.to_python({(1, 2): 3}, mode='json') == {'1,2': 3} | ||
assert s.to_json({(1, 2): 3}) == b'{"1,2":3}' | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'value,expected_python,expected_json', | ||
[(None, 'None', b'"None"'), (1, '1', b'"1"'), ([1, 2, 3], '[1, 2, 3]', b'"[1, 2, 3]"')], | ||
) | ||
def test_schema_serializer_capturing_function(value, expected_python, expected_json): | ||
# Test a SchemaSerializer that captures a function. | ||
s = SchemaSerializer( | ||
core_schema.any_schema( | ||
serialization=core_schema.plain_serializer_function_ser_schema(repr_function, info_arg=True) | ||
) | ||
) | ||
s = pickle.loads(pickle.dumps(s)) | ||
assert s.to_python(value) == expected_python | ||
assert s.to_json(value) == expected_json | ||
assert s.to_python(value, mode='json') == json.loads(expected_json) | ||
|
||
|
||
def test_schema_serializer_containing_config(): | ||
s = SchemaSerializer(core_schema.timedelta_schema(), config={'ser_json_timedelta': 'float'}) | ||
s = pickle.loads(pickle.dumps(s)) | ||
|
||
assert s.to_python(timedelta(seconds=4, microseconds=500_000)) == timedelta(seconds=4, microseconds=500_000) | ||
assert s.to_python(timedelta(seconds=4, microseconds=500_000), mode='json') == 4.5 | ||
assert s.to_json(timedelta(seconds=4, microseconds=500_000)) == b'4.5' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import pickle | ||
import re | ||
from datetime import datetime, timedelta, timezone | ||
|
||
import pytest | ||
|
||
from pydantic_core import core_schema, validate_core_schema | ||
from pydantic_core._pydantic_core import SchemaValidator, ValidationError | ||
|
||
|
||
def test_basic_schema_validator(): | ||
v = SchemaValidator( | ||
validate_core_schema( | ||
{'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 |