@@ -46,3 +46,123 @@ class OuterModel:
4646 result = outer_validator .validate_python ({'inner' : {'x' : 1 }})
4747 assert result .inner .x == 1
4848 assert outer_serializer .to_python (result ) == {'inner' : {'x' : 1 }}
49+
50+
51+ def test_prebuilt_not_used_for_wrap_serializer_functions () -> None :
52+ class InnerModel :
53+ x : str
54+
55+ def __init__ (self , x : str ) -> None :
56+ self .x = x
57+
58+ def serialize_inner (v : InnerModel , serializer ) -> str :
59+ v .x = v .x + ' modified'
60+ return serializer (v )
61+
62+ inner_schema = core_schema .model_schema (
63+ InnerModel ,
64+ schema = core_schema .model_fields_schema (
65+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
66+ ),
67+ serialization = core_schema .wrap_serializer_function_ser_schema (serialize_inner ),
68+ )
69+
70+ inner_schema_serializer = SchemaSerializer (inner_schema )
71+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
72+ InnerModel .__pydantic_serializer__ = inner_schema_serializer # pyright: ignore[reportAttributeAccessIssue]
73+
74+ class OuterModel :
75+ inner : InnerModel
76+
77+ def __init__ (self , inner : InnerModel ) -> None :
78+ self .inner = inner
79+
80+ outer_schema = core_schema .model_schema (
81+ OuterModel ,
82+ schema = core_schema .model_fields_schema (
83+ {
84+ 'inner' : core_schema .model_field (
85+ schema = core_schema .model_schema (
86+ InnerModel ,
87+ schema = core_schema .model_fields_schema (
88+ # note, we use a simple str schema (with no custom serialization)
89+ # in order to verify that the prebuilt serializer from InnerModel is not used
90+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
91+ ),
92+ )
93+ )
94+ }
95+ ),
96+ )
97+
98+ inner_serializer = SchemaSerializer (inner_schema )
99+ outer_serializer = SchemaSerializer (outer_schema )
100+
101+ # the custom serialization function does apply for the inner model
102+ inner_instance = InnerModel (x = 'hello' )
103+ assert inner_serializer .to_python (inner_instance ) == {'x' : 'hello modified' }
104+
105+ # but the outer model doesn't reuse the custom wrap serializer function, so we see simple str ser
106+ outer_instance = OuterModel (inner = InnerModel (x = 'hello' ))
107+ assert outer_serializer .to_python (outer_instance ) == {'inner' : {'x' : 'hello' }}
108+
109+
110+ def test_prebuilt_not_used_for_wrap_validator_functions () -> None :
111+ class InnerModel :
112+ x : str
113+
114+ def __init__ (self , x : str ) -> None :
115+ self .x = x
116+
117+ def validate_inner (data , validator ) -> str :
118+ data ['x' ] = data ['x' ] + ' modified'
119+ return validator (data )
120+
121+ inner_schema = core_schema .no_info_wrap_validator_function (
122+ validate_inner ,
123+ core_schema .model_schema (
124+ InnerModel ,
125+ schema = core_schema .model_fields_schema (
126+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
127+ ),
128+ ),
129+ )
130+
131+ inner_schema_validator = SchemaValidator (inner_schema )
132+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
133+ InnerModel .__pydantic_validator__ = inner_schema_validator # pyright: ignore[reportAttributeAccessIssue]
134+
135+ class OuterModel :
136+ inner : InnerModel
137+
138+ def __init__ (self , inner : InnerModel ) -> None :
139+ self .inner = inner
140+
141+ outer_schema = core_schema .model_schema (
142+ OuterModel ,
143+ schema = core_schema .model_fields_schema (
144+ {
145+ 'inner' : core_schema .model_field (
146+ schema = core_schema .model_schema (
147+ InnerModel ,
148+ schema = core_schema .model_fields_schema (
149+ # note, we use a simple str schema (with no custom validation)
150+ # in order to verify that the prebuilt validator from InnerModel is not used
151+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
152+ ),
153+ )
154+ )
155+ }
156+ ),
157+ )
158+
159+ inner_validator = SchemaValidator (inner_schema )
160+ outer_validator = SchemaValidator (outer_schema )
161+
162+ # the custom validation function does apply for the inner model
163+ result_inner = inner_validator .validate_python ({'x' : 'hello' })
164+ assert result_inner .x == 'hello modified'
165+
166+ # but the outer model doesn't reuse the custom wrap validator function, so we see simple str val
167+ result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
168+ assert result_outer .inner .x == 'hello'
0 commit comments