@@ -14,11 +14,11 @@ class InnerModel:
14
14
),
15
15
)
16
16
17
- inner_schema_validator = SchemaValidator (inner_schema )
18
- inner_schema_serializer = SchemaSerializer (inner_schema )
17
+ inner_validator = SchemaValidator (inner_schema )
18
+ inner_serializer = SchemaSerializer (inner_schema )
19
19
InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
20
- InnerModel .__pydantic_validator__ = inner_schema_validator # pyright: ignore[reportAttributeAccessIssue]
21
- InnerModel .__pydantic_serializer__ = inner_schema_serializer # pyright: ignore[reportAttributeAccessIssue]
20
+ InnerModel .__pydantic_validator__ = inner_validator # pyright: ignore[reportAttributeAccessIssue]
21
+ InnerModel .__pydantic_serializer__ = inner_serializer # pyright: ignore[reportAttributeAccessIssue]
22
22
23
23
class OuterModel :
24
24
inner : InnerModel
@@ -69,9 +69,9 @@ def serialize_inner(v: InnerModel, serializer) -> Union[dict[str, str], str]:
69
69
serialization = core_schema .wrap_serializer_function_ser_schema (serialize_inner ),
70
70
)
71
71
72
- inner_schema_serializer = SchemaSerializer (inner_schema )
72
+ inner_serializer = SchemaSerializer (inner_schema )
73
73
InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
74
- InnerModel .__pydantic_serializer__ = inner_schema_serializer # pyright: ignore[reportAttributeAccessIssue]
74
+ InnerModel .__pydantic_serializer__ = inner_serializer # pyright: ignore[reportAttributeAccessIssue]
75
75
76
76
class OuterModel :
77
77
inner : InnerModel
@@ -97,7 +97,6 @@ def __init__(self, inner: InnerModel) -> None:
97
97
),
98
98
)
99
99
100
- inner_serializer = SchemaSerializer (inner_schema )
101
100
outer_serializer = SchemaSerializer (outer_schema )
102
101
103
102
# the custom serialization function does apply for the inner model
@@ -130,9 +129,9 @@ def validate_inner(data, validator) -> InnerModel:
130
129
),
131
130
)
132
131
133
- inner_schema_validator = SchemaValidator (inner_schema )
132
+ inner_validator = SchemaValidator (inner_schema )
134
133
InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
135
- InnerModel .__pydantic_validator__ = inner_schema_validator # pyright: ignore[reportAttributeAccessIssue]
134
+ InnerModel .__pydantic_validator__ = inner_validator # pyright: ignore[reportAttributeAccessIssue]
136
135
137
136
class OuterModel :
138
137
inner : InnerModel
@@ -158,7 +157,6 @@ def __init__(self, inner: InnerModel) -> None:
158
157
),
159
158
)
160
159
161
- inner_validator = SchemaValidator (inner_schema )
162
160
outer_validator = SchemaValidator (outer_schema )
163
161
164
162
# the custom validation function does apply for the inner model
@@ -170,6 +168,66 @@ def __init__(self, inner: InnerModel) -> None:
170
168
assert result_outer .inner .x == 'hello'
171
169
172
170
171
+ def test_prebuilt_not_used_for_after_validator_functions () -> None :
172
+ class InnerModel :
173
+ x : str
174
+
175
+ def __init__ (self , x : str ) -> None :
176
+ self .x = x
177
+
178
+ def validate_after (self ) -> InnerModel :
179
+ self .x = self .x + ' modified'
180
+ return self
181
+
182
+ inner_schema = core_schema .no_info_after_validator_function (
183
+ validate_after ,
184
+ core_schema .model_schema (
185
+ InnerModel ,
186
+ schema = core_schema .model_fields_schema (
187
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
188
+ ),
189
+ ),
190
+ )
191
+
192
+ inner_validator = SchemaValidator (inner_schema )
193
+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
194
+ InnerModel .__pydantic_validator__ = inner_validator # pyright: ignore[reportAttributeAccessIssue]
195
+
196
+ class OuterModel :
197
+ inner : InnerModel
198
+
199
+ def __init__ (self , inner : InnerModel ) -> None :
200
+ self .inner = inner
201
+
202
+ outer_schema = core_schema .model_schema (
203
+ OuterModel ,
204
+ schema = core_schema .model_fields_schema (
205
+ {
206
+ 'inner' : core_schema .model_field (
207
+ schema = core_schema .model_schema (
208
+ InnerModel ,
209
+ schema = core_schema .model_fields_schema (
210
+ # note, we use a simple str schema (with no custom validation)
211
+ # in order to verify that the prebuilt validator from InnerModel is not used
212
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
213
+ ),
214
+ )
215
+ )
216
+ }
217
+ ),
218
+ )
219
+
220
+ outer_validator = SchemaValidator (outer_schema )
221
+
222
+ # the custom validation function does apply for the inner model
223
+ result_inner = inner_validator .validate_python ({'x' : 'hello' })
224
+ assert result_inner .x == 'hello modified'
225
+
226
+ # but the outer model doesn't reuse the custom after validator function, so we see simple str val
227
+ result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
228
+ assert result_outer .inner .x == 'hello'
229
+
230
+
173
231
def test_reuse_plain_serializer_ok () -> None :
174
232
class InnerModel :
175
233
x : str
@@ -188,9 +246,9 @@ def serialize_inner(v: InnerModel) -> str:
188
246
serialization = core_schema .plain_serializer_function_ser_schema (serialize_inner ),
189
247
)
190
248
191
- inner_schema_serializer = SchemaSerializer (inner_schema )
249
+ inner_serializer = SchemaSerializer (inner_schema )
192
250
InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
193
- InnerModel .__pydantic_serializer__ = inner_schema_serializer # pyright: ignore[reportAttributeAccessIssue]
251
+ InnerModel .__pydantic_serializer__ = inner_serializer # pyright: ignore[reportAttributeAccessIssue]
194
252
195
253
class OuterModel :
196
254
inner : InnerModel
@@ -216,7 +274,6 @@ def __init__(self, inner: InnerModel) -> None:
216
274
),
217
275
)
218
276
219
- inner_serializer = SchemaSerializer (inner_schema )
220
277
outer_serializer = SchemaSerializer (outer_schema )
221
278
222
279
# the custom serialization function does apply for the inner model
@@ -243,9 +300,9 @@ def validate_inner(data) -> InnerModel:
243
300
244
301
inner_schema = core_schema .no_info_plain_validator_function (validate_inner )
245
302
246
- inner_schema_validator = SchemaValidator (inner_schema )
303
+ inner_validator = SchemaValidator (inner_schema )
247
304
InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
248
- InnerModel .__pydantic_validator__ = inner_schema_validator # pyright: ignore[reportAttributeAccessIssue]
305
+ InnerModel .__pydantic_validator__ = inner_validator # pyright: ignore[reportAttributeAccessIssue]
249
306
250
307
class OuterModel :
251
308
inner : InnerModel
@@ -271,7 +328,6 @@ def __init__(self, inner: InnerModel) -> None:
271
328
),
272
329
)
273
330
274
- inner_validator = SchemaValidator (inner_schema )
275
331
outer_validator = SchemaValidator (outer_schema )
276
332
277
333
# the custom validation function does apply for the inner model
@@ -283,3 +339,67 @@ def __init__(self, inner: InnerModel) -> None:
283
339
result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
284
340
assert result_outer .inner .x == 'hello modified'
285
341
assert 'PrebuiltValidator' in repr (outer_validator )
342
+
343
+
344
+ def test_reuse_before_validator_ok () -> None :
345
+ class InnerModel :
346
+ x : str
347
+
348
+ def __init__ (self , x : str ) -> None :
349
+ self .x = x
350
+
351
+ def validate_before (data ) -> dict :
352
+ data ['x' ] = data ['x' ] + ' modified'
353
+ return data
354
+
355
+ inner_schema = core_schema .no_info_before_validator_function (
356
+ validate_before ,
357
+ core_schema .model_schema (
358
+ InnerModel ,
359
+ schema = core_schema .model_fields_schema (
360
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
361
+ ),
362
+ ),
363
+ )
364
+
365
+ inner_validator = SchemaValidator (inner_schema )
366
+ InnerModel .__pydantic_complete__ = True # pyright: ignore[reportAttributeAccessIssue]
367
+ InnerModel .__pydantic_validator__ = inner_validator # pyright: ignore[reportAttributeAccessIssue]
368
+
369
+ class OuterModel :
370
+ inner : InnerModel
371
+
372
+ def __init__ (self , inner : InnerModel ) -> None :
373
+ self .inner = inner
374
+
375
+ outer_schema = core_schema .model_schema (
376
+ OuterModel ,
377
+ schema = core_schema .model_fields_schema (
378
+ {
379
+ 'inner' : core_schema .model_field (
380
+ schema = core_schema .model_schema (
381
+ InnerModel ,
382
+ schema = core_schema .model_fields_schema (
383
+ # note, we use a simple str schema (with no custom validation)
384
+ # in order to verify that the prebuilt validator from InnerModel is used instead
385
+ {'x' : core_schema .model_field (schema = core_schema .str_schema ())},
386
+ ),
387
+ )
388
+ )
389
+ }
390
+ ),
391
+ )
392
+
393
+ outer_validator = SchemaValidator (outer_schema )
394
+ print (inner_validator )
395
+ print (outer_validator )
396
+
397
+ # the custom validation function does apply for the inner model
398
+ result_inner = inner_validator .validate_python ({'x' : 'hello' })
399
+ assert result_inner .x == 'hello modified'
400
+ assert 'FunctionBeforeValidator' in repr (inner_validator )
401
+
402
+ # the custom validation function does apply for the outer model as well, a before validator is permitted as a prebuilt candidate
403
+ result_outer = outer_validator .validate_python ({'inner' : {'x' : 'hello' }})
404
+ assert result_outer .inner .x == 'hello modified'
405
+ assert 'PrebuiltValidator' in repr (outer_validator )
0 commit comments