From 7b5c8ce068bc289628f71dce6d9651a3d44f5e09 Mon Sep 17 00:00:00 2001 From: nix Date: Mon, 1 Jul 2024 19:40:32 +0700 Subject: [PATCH 1/3] fix serialize_as_any with recursive ref --- .../type_serializers/definitions.rs | 21 +++++++---- tests/serializers/test_serialize_as_any.py | 36 +++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/serializers/type_serializers/definitions.rs b/src/serializers/type_serializers/definitions.rs index 071e50f8c..d66d39172 100644 --- a/src/serializers/type_serializers/definitions.rs +++ b/src/serializers/type_serializers/definitions.rs @@ -7,6 +7,7 @@ use pyo3::types::{PyDict, PyList}; use crate::definitions::DefinitionsBuilder; use crate::definitions::{DefinitionRef, RecursionSafeCache}; +use crate::serializers::DuckTypingSerMode; use crate::tools::SchemaDict; @@ -93,8 +94,12 @@ impl TypeSerializer for DefinitionRefSerializer { ) -> PyResult { self.definition.read(|comb_serializer| { let comb_serializer = comb_serializer.unwrap(); - let mut guard = extra.recursion_guard(value, self.definition.id())?; - comb_serializer.to_python(value, include, exclude, guard.state()) + if extra.duck_typing_ser_mode != DuckTypingSerMode::Inferred { + comb_serializer.to_python(value, include, exclude, extra) + } else { + let mut guard = extra.recursion_guard(value, self.definition.id())?; + comb_serializer.to_python(value, include, exclude, guard.state()) + } }) } @@ -112,10 +117,14 @@ impl TypeSerializer for DefinitionRefSerializer { ) -> Result { self.definition.read(|comb_serializer| { let comb_serializer = comb_serializer.unwrap(); - let mut guard = extra - .recursion_guard(value, self.definition.id()) - .map_err(py_err_se_err)?; - comb_serializer.serde_serialize(value, serializer, include, exclude, guard.state()) + if extra.duck_typing_ser_mode != DuckTypingSerMode::Inferred { + comb_serializer.serde_serialize(value, serializer, include, exclude, extra) + } else { + let mut guard = extra + .recursion_guard(value, self.definition.id()) + .map_err(py_err_se_err)?; + comb_serializer.serde_serialize(value, serializer, include, exclude, guard.state()) + } }) } diff --git a/tests/serializers/test_serialize_as_any.py b/tests/serializers/test_serialize_as_any.py index 1d1be238b..dd4713c06 100644 --- a/tests/serializers/test_serialize_as_any.py +++ b/tests/serializers/test_serialize_as_any.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from typing import Optional from typing_extensions import TypedDict @@ -155,3 +156,38 @@ class Other: 'x': 1, 'y': 'hopefully not a secret', } + + +def test_serialize_with_recursive_models() -> None: + + class Node: + next: Optional['Node'] = None + value: int = 42 + + schema = core_schema.definitions_schema( + core_schema.definition_reference_schema('Node'), + [ + core_schema.model_schema( + Node, + core_schema.model_fields_schema( + { + 'value': core_schema.model_field(core_schema.with_default_schema(core_schema.int_schema(), default=42)), + 'next': core_schema.model_field( + core_schema.with_default_schema( + core_schema.nullable_schema( + core_schema.definition_reference_schema('Node') + ), + default=None, + ) + ), + } + ), + ref='Node', + ) + ], + ) + + s = SchemaSerializer(schema) + v = SchemaValidator(schema) + + obj = v.validate_python({'value': 2, 'asdas': 1}) \ No newline at end of file From 1976e36d70f3041130362092be9620a26864082d Mon Sep 17 00:00:00 2001 From: nix Date: Sat, 28 Sep 2024 13:45:12 +0700 Subject: [PATCH 2/3] fix ci failed on build up memory stack --- src/serializers/extra.rs | 4 ++++ src/serializers/type_serializers/definitions.rs | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/serializers/extra.rs b/src/serializers/extra.rs index dbf6f7b31..50e9b76a3 100644 --- a/src/serializers/extra.rs +++ b/src/serializers/extra.rs @@ -47,6 +47,10 @@ impl DuckTypingSerMode { } } + pub fn is_need_inference(self) -> bool { + self == DuckTypingSerMode::NeedsInference + } + pub fn to_bool(self) -> bool { match self { DuckTypingSerMode::SchemaBased => false, diff --git a/src/serializers/type_serializers/definitions.rs b/src/serializers/type_serializers/definitions.rs index d66d39172..ba70fe5dd 100644 --- a/src/serializers/type_serializers/definitions.rs +++ b/src/serializers/type_serializers/definitions.rs @@ -94,7 +94,7 @@ impl TypeSerializer for DefinitionRefSerializer { ) -> PyResult { self.definition.read(|comb_serializer| { let comb_serializer = comb_serializer.unwrap(); - if extra.duck_typing_ser_mode != DuckTypingSerMode::Inferred { + if extra.duck_typing_ser_mode == DuckTypingSerMode::NeedsInference { comb_serializer.to_python(value, include, exclude, extra) } else { let mut guard = extra.recursion_guard(value, self.definition.id())?; @@ -117,7 +117,7 @@ impl TypeSerializer for DefinitionRefSerializer { ) -> Result { self.definition.read(|comb_serializer| { let comb_serializer = comb_serializer.unwrap(); - if extra.duck_typing_ser_mode != DuckTypingSerMode::Inferred { + if extra.duck_typing_ser_mode.is_need_inference() { comb_serializer.serde_serialize(value, serializer, include, exclude, extra) } else { let mut guard = extra From f51a195ae14b5d8953dbfe2f827bec5665a6efe9 Mon Sep 17 00:00:00 2001 From: nix Date: Sat, 28 Sep 2024 14:13:47 +0700 Subject: [PATCH 3/3] add test --- tests/serializers/test_serialize_as_any.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/serializers/test_serialize_as_any.py b/tests/serializers/test_serialize_as_any.py index dd4713c06..ea7e7fd67 100644 --- a/tests/serializers/test_serialize_as_any.py +++ b/tests/serializers/test_serialize_as_any.py @@ -159,7 +159,6 @@ class Other: def test_serialize_with_recursive_models() -> None: - class Node: next: Optional['Node'] = None value: int = 42 @@ -171,12 +170,12 @@ class Node: Node, core_schema.model_fields_schema( { - 'value': core_schema.model_field(core_schema.with_default_schema(core_schema.int_schema(), default=42)), + 'value': core_schema.model_field( + core_schema.with_default_schema(core_schema.int_schema(), default=42) + ), 'next': core_schema.model_field( core_schema.with_default_schema( - core_schema.nullable_schema( - core_schema.definition_reference_schema('Node') - ), + core_schema.nullable_schema(core_schema.definition_reference_schema('Node')), default=None, ) ), @@ -187,7 +186,12 @@ class Node: ], ) - s = SchemaSerializer(schema) - v = SchemaValidator(schema) + Node.__pydantic_core_schema__ = schema + Node.__pydantic_validator__ = SchemaValidator(Node.__pydantic_core_schema__) + Node.__pydantic_serializer__ = SchemaSerializer(Node.__pydantic_core_schema__) + other = Node.__pydantic_validator__.validate_python({'next': {'value': 4}}) - obj = v.validate_python({'value': 2, 'asdas': 1}) \ No newline at end of file + assert Node.__pydantic_serializer__.to_python(other, serialize_as_any=True) == { + 'next': {'next': None, 'value': 4}, + 'value': 42, + }