From 202a25157e29851252dfe09a37a001517dfa0ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Nad=C3=A9?= Date: Sun, 14 Jan 2024 00:56:59 +0100 Subject: [PATCH 1/5] propagate serialization information in PlainValidator schema creation process MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Nadé --- pydantic/functional_validators.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pydantic/functional_validators.py b/pydantic/functional_validators.py index 0914528469..486bd5fbc0 100644 --- a/pydantic/functional_validators.py +++ b/pydantic/functional_validators.py @@ -153,13 +153,17 @@ class Model(BaseModel): func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction def __get_pydantic_core_schema__(self, source_type: Any, handler: _GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + serialization = schema.get('serialization', None) info_arg = _inspect_validator(self.func, 'plain') if info_arg: func = cast(core_schema.WithInfoValidatorFunction, self.func) - return core_schema.with_info_plain_validator_function(func, field_name=handler.field_name) + return core_schema.with_info_plain_validator_function( + func, field_name=handler.field_name, serialization=serialization + ) else: func = cast(core_schema.NoInfoValidatorFunction, self.func) - return core_schema.no_info_plain_validator_function(func) + return core_schema.no_info_plain_validator_function(func, serialization=serialization) @dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) From 33dc02cb7e273755e41a7bbe85141f4f411b3bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Nad=C3=A9?= Date: Mon, 15 Jan 2024 21:12:52 +0100 Subject: [PATCH 2/5] Test that PlainValidator actually keep serialization information in the schema MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Nadé --- tests/test_validators.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/test_validators.py b/tests/test_validators.py index 2dcf20fa5c..e5376c6576 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -20,6 +20,7 @@ ConfigDict, Field, GetCoreSchemaHandler, + PlainSerializer, PydanticDeprecatedSince20, PydanticUserError, TypeAdapter, @@ -2810,3 +2811,18 @@ def value_b_validator(cls, value): 'ctx': {'error': IsInstance(AssertionError)}, }, ] + + +def test_plain_validator_plain_serializer() -> None: + ser_type = str + + class Blah(BaseModel): + enabled: Annotated[ + bool, + PlainSerializer(lambda x: ser_type(int(x)), return_type=ser_type), + PlainValidator(lambda x: bool(int(x))), + ] + + blah = Blah(enabled='0') + data = blah.model_dump() + assert isinstance(data['enabled'], ser_type) From b10e771067a120495f2e49e68e242999c4500ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Nad=C3=A9?= Date: Wed, 17 Jan 2024 00:44:37 +0100 Subject: [PATCH 3/5] ensure correct type is used for serialization in PlainValidator using core_schema.wrap_serializer_function_ser_schema --- pydantic/functional_validators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydantic/functional_validators.py b/pydantic/functional_validators.py index 486bd5fbc0..f11d212fe7 100644 --- a/pydantic/functional_validators.py +++ b/pydantic/functional_validators.py @@ -154,7 +154,7 @@ class Model(BaseModel): def __get_pydantic_core_schema__(self, source_type: Any, handler: _GetCoreSchemaHandler) -> core_schema.CoreSchema: schema = handler(source_type) - serialization = schema.get('serialization', None) + serialization = core_schema.wrap_serializer_function_ser_schema(function=lambda v, h: h(v), schema=schema) info_arg = _inspect_validator(self.func, 'plain') if info_arg: func = cast(core_schema.WithInfoValidatorFunction, self.func) From dac27ff319d919d01f532bd6ab73ce308a90589e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Nad=C3=A9?= Date: Wed, 17 Jan 2024 21:58:36 +0100 Subject: [PATCH 4/5] put both serializer/validator combinations in test_plain_validator_plain_serializer --- tests/test_validators.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_validators.py b/tests/test_validators.py index e5376c6576..fe0bcc8956 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2815,14 +2815,14 @@ def value_b_validator(cls, value): def test_plain_validator_plain_serializer() -> None: ser_type = str + serializer = PlainSerializer(lambda x: ser_type(int(x)), return_type=ser_type) + validator = PlainValidator(lambda x: bool(int(x))) class Blah(BaseModel): - enabled: Annotated[ - bool, - PlainSerializer(lambda x: ser_type(int(x)), return_type=ser_type), - PlainValidator(lambda x: bool(int(x))), - ] + foo: Annotated[bool, validator, serializer] + bar: Annotated[bool, serializer, validator] - blah = Blah(enabled='0') + blah = Blah(foo='0', bar='1') data = blah.model_dump() - assert isinstance(data['enabled'], ser_type) + assert isinstance(data['foo'], ser_type) + assert isinstance(data['bar'], ser_type) From 1c222e9ca7936bc495bd8d67b76d94d27fb9ebb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damien=20Nad=C3=A9?= Date: Wed, 17 Jan 2024 22:02:56 +0100 Subject: [PATCH 5/5] add bug reference as test_plain_validator_plain_serializer docstring --- tests/test_validators.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_validators.py b/tests/test_validators.py index fe0bcc8956..720b79690b 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -2814,6 +2814,7 @@ def value_b_validator(cls, value): def test_plain_validator_plain_serializer() -> None: + """https://github.com/pydantic/pydantic/issues/8512""" ser_type = str serializer = PlainSerializer(lambda x: ser_type(int(x)), return_type=ser_type) validator = PlainValidator(lambda x: bool(int(x)))