@@ -55,7 +55,7 @@ class InnerModel:
55
55
def __init__ (self , x : str ) -> None :
56
56
self .x = x
57
57
58
- def serialize_inner (v : InnerModel , serializer ) -> str :
58
+ def serialize_inner (v : InnerModel , serializer ) -> dict [ str , str ] | str :
59
59
v .x = v .x + ' modified'
60
60
return serializer (v )
61
61
@@ -114,7 +114,7 @@ class InnerModel:
114
114
def __init__ (self , x : str ) -> None :
115
115
self .x = x
116
116
117
- def validate_inner (data , validator ) -> str :
117
+ def validate_inner (data , validator ) -> InnerModel :
118
118
data ['x' ] = data ['x' ] + ' modified'
119
119
return validator (data )
120
120
@@ -166,3 +166,118 @@ def __init__(self, inner: InnerModel) -> None:
166
166
# but the outer model doesn't reuse the custom wrap validator function, so we see simple str val
167
167
result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
168
168
assert result_outer .inner .x == 'hello'
169
+
170
+
171
+ def test_reuse_plain_serializer_ok () -> None :
172
+ class InnerModel :
173
+ x : str
174
+
175
+ def __init__ (self , x : str ) -> None :
176
+ self .x = x
177
+
178
+ def serialize_inner (v : InnerModel ) -> str :
179
+ return v .x + ' modified'
180
+
181
+ inner_schema = core_schema .model_schema (
182
+ InnerModel ,
183
+ schema = core_schema .model_fields_schema (
184
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
185
+ ),
186
+ serialization = core_schema .plain_serializer_function_ser_schema (serialize_inner ),
187
+ )
188
+
189
+ inner_schema_serializer = SchemaSerializer (inner_schema )
190
+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
191
+ InnerModel .__pydantic_serializer__ = inner_schema_serializer # pyright: ignore[reportAttributeAccessIssue]
192
+
193
+ class OuterModel :
194
+ inner : InnerModel
195
+
196
+ def __init__ (self , inner : InnerModel ) -> None :
197
+ self .inner = inner
198
+
199
+ outer_schema = core_schema .model_schema (
200
+ OuterModel ,
201
+ schema = core_schema .model_fields_schema (
202
+ {
203
+ 'inner' : core_schema .model_field (
204
+ schema = core_schema .model_schema (
205
+ InnerModel ,
206
+ schema = core_schema .model_fields_schema (
207
+ # note, we use a simple str schema (with no custom serialization)
208
+ # in order to verify that the prebuilt serializer from InnerModel is used instead
209
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
210
+ ),
211
+ )
212
+ )
213
+ }
214
+ ),
215
+ )
216
+
217
+ inner_serializer = SchemaSerializer (inner_schema )
218
+ outer_serializer = SchemaSerializer (outer_schema )
219
+
220
+ # the custom serialization function does apply for the inner model
221
+ inner_instance = InnerModel (x = 'hello' )
222
+ assert inner_serializer .to_python (inner_instance ) == 'hello modified'
223
+ assert 'FunctionPlainSerializer' in repr (inner_serializer )
224
+
225
+ # the custom ser function applies for the outer model as well, a plain serializer is permitted as a prebuilt candidate
226
+ outer_instance = OuterModel (inner = InnerModel (x = 'hello' ))
227
+ assert outer_serializer .to_python (outer_instance ) == {'inner' : 'hello modified' }
228
+ assert 'PrebuiltSerializer' in repr (outer_serializer )
229
+
230
+
231
+ def test_reuse_plain_validator_ok () -> None :
232
+ class InnerModel :
233
+ x : str
234
+
235
+ def __init__ (self , x : str ) -> None :
236
+ self .x = x
237
+
238
+ def validate_inner (data ) -> InnerModel :
239
+ data ['x' ] = data ['x' ] + ' modified'
240
+ return InnerModel (** data )
241
+
242
+ inner_schema = core_schema .no_info_plain_validator_function (validate_inner )
243
+
244
+ inner_schema_validator = SchemaValidator (inner_schema )
245
+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
246
+ InnerModel .__pydantic_validator__ = inner_schema_validator # pyright: ignore[reportAttributeAccessIssue]
247
+
248
+ class OuterModel :
249
+ inner : InnerModel
250
+
251
+ def __init__ (self , inner : InnerModel ) -> None :
252
+ self .inner = inner
253
+
254
+ outer_schema = core_schema .model_schema (
255
+ OuterModel ,
256
+ schema = core_schema .model_fields_schema (
257
+ {
258
+ 'inner' : core_schema .model_field (
259
+ schema = core_schema .model_schema (
260
+ InnerModel ,
261
+ schema = core_schema .model_fields_schema (
262
+ # note, we use a simple str schema (with no custom validation)
263
+ # in order to verify that the prebuilt validator from InnerModel is used instead
264
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
265
+ ),
266
+ )
267
+ )
268
+ }
269
+ ),
270
+ )
271
+
272
+ inner_validator = SchemaValidator (inner_schema )
273
+ outer_validator = SchemaValidator (outer_schema )
274
+
275
+ # the custom validation function does apply for the inner model
276
+ result_inner = inner_validator .validate_python ({'x' : 'hello' })
277
+ assert result_inner .x == 'hello modified'
278
+ assert 'FunctionPlainValidator' in repr (inner_validator )
279
+
280
+ # the custom validation function does apply for the outer model as well, a plain validator is permitted as a prebuilt candidate
281
+ result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
282
+ assert result_outer .inner .x == 'hello modified'
283
+ assert 'PrebuiltValidator' in repr (outer_validator )
0 commit comments