@@ -72,134 +72,124 @@ impl UnionSerializer {
72
72
73
73
impl_py_gc_traverse ! ( UnionSerializer { choices } ) ;
74
74
75
- impl TypeSerializer for UnionSerializer {
76
- fn to_python (
77
- & self ,
78
- value : & Bound < ' _ , PyAny > ,
79
- include : Option < & Bound < ' _ , PyAny > > ,
80
- exclude : Option < & Bound < ' _ , PyAny > > ,
81
- extra : & Extra ,
82
- ) -> PyResult < PyObject > {
83
- to_python ( value, include, exclude, extra, & self . choices , self . get_name ( ) )
84
- }
75
+ fn to_python (
76
+ value : & Bound < ' _ , PyAny > ,
77
+ include : Option < & Bound < ' _ , PyAny > > ,
78
+ exclude : Option < & Bound < ' _ , PyAny > > ,
79
+ extra : & Extra ,
80
+ choices : & [ CombinedSerializer ] ,
81
+ name : & str ,
82
+ retry_with_lax_check : bool ,
83
+ ) -> PyResult < PyObject > {
84
+ // try the serializers in left to right order with error_on fallback=true
85
+ let mut new_extra = extra. clone ( ) ;
86
+ new_extra. check = SerCheck :: Strict ;
87
+ let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
85
88
86
- fn json_key < ' a > ( & self , key : & ' a Bound < ' _ , PyAny > , extra : & Extra ) -> PyResult < Cow < ' a , str > > {
87
- let mut new_extra = extra. clone ( ) ;
88
- new_extra. check = SerCheck :: Strict ;
89
- let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
89
+ for comb_serializer in choices. clone ( ) {
90
+ match comb_serializer. to_python ( value, include, exclude, & new_extra) {
91
+ Ok ( v) => return Ok ( v) ,
92
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value. py ( ) ) {
93
+ true => ( ) ,
94
+ false => errors. push ( err) ,
95
+ } ,
96
+ }
97
+ }
90
98
91
- for comb_serializer in & self . choices {
92
- match comb_serializer. json_key ( key, & new_extra) {
99
+ if retry_with_lax_check {
100
+ new_extra. check = SerCheck :: Lax ;
101
+ for comb_serializer in choices {
102
+ match comb_serializer. to_python ( value, include, exclude, & new_extra) {
93
103
Ok ( v) => return Ok ( v) ,
94
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( key . py ( ) ) {
104
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value . py ( ) ) {
95
105
true => ( ) ,
96
106
false => errors. push ( err) ,
97
107
} ,
98
108
}
99
109
}
100
- if self . retry_with_lax_check ( ) {
101
- new_extra. check = SerCheck :: Lax ;
102
- for comb_serializer in & self . choices {
103
- match comb_serializer. json_key ( key, & new_extra) {
104
- Ok ( v) => return Ok ( v) ,
105
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( key. py ( ) ) {
106
- true => ( ) ,
107
- false => errors. push ( err) ,
108
- } ,
109
- }
110
- }
111
- }
112
-
113
- for err in & errors {
114
- extra. warnings . custom_warning ( err. to_string ( ) ) ;
115
- }
110
+ }
116
111
117
- extra . warnings . on_fallback_py ( self . get_name ( ) , key , extra ) ? ;
118
- infer_json_key ( key , extra)
112
+ for err in & errors {
113
+ extra. warnings . custom_warning ( err . to_string ( ) ) ;
119
114
}
120
115
121
- fn serde_serialize < S : serde:: ser:: Serializer > (
122
- & self ,
123
- value : & Bound < ' _ , PyAny > ,
124
- serializer : S ,
125
- include : Option < & Bound < ' _ , PyAny > > ,
126
- exclude : Option < & Bound < ' _ , PyAny > > ,
127
- extra : & Extra ,
128
- ) -> Result < S :: Ok , S :: Error > {
129
- let py = value. py ( ) ;
130
- let mut new_extra = extra. clone ( ) ;
131
- new_extra. check = SerCheck :: Strict ;
132
- let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
116
+ extra. warnings . on_fallback_py ( name, value, extra) ?;
117
+ infer_to_python ( value, include, exclude, extra)
118
+ }
133
119
134
- for comb_serializer in & self . choices {
135
- match comb_serializer. to_python ( value, include, exclude, & new_extra) {
136
- Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
137
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value. py ( ) ) {
120
+ fn json_key (
121
+ key : & Bound < ' _ , PyAny > ,
122
+ extra : & Extra ,
123
+ choices : & [ CombinedSerializer ] ,
124
+ name : & str ,
125
+ retry_with_lax_check : bool ,
126
+ ) -> PyResult < Cow < str > > {
127
+ let mut new_extra = extra. clone ( ) ;
128
+ new_extra. check = SerCheck :: Strict ;
129
+ let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
130
+
131
+ for comb_serializer in choices. clone ( ) {
132
+ match comb_serializer. json_key ( key, & new_extra) {
133
+ Ok ( v) => return Ok ( v) ,
134
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( key. py ( ) ) {
135
+ true => ( ) ,
136
+ false => errors. push ( err) ,
137
+ } ,
138
+ }
139
+ }
140
+
141
+ if retry_with_lax_check {
142
+ new_extra. check = SerCheck :: Lax ;
143
+ for comb_serializer in choices {
144
+ match comb_serializer. json_key ( key, & new_extra) {
145
+ Ok ( v) => return Ok ( v) ,
146
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( key. py ( ) ) {
138
147
true => ( ) ,
139
148
false => errors. push ( err) ,
140
149
} ,
141
150
}
142
151
}
143
- if self . retry_with_lax_check ( ) {
144
- new_extra. check = SerCheck :: Lax ;
145
- for comb_serializer in & self . choices {
146
- match comb_serializer. to_python ( value, include, exclude, & new_extra) {
147
- Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
148
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value. py ( ) ) {
149
- true => ( ) ,
150
- false => errors. push ( err) ,
151
- } ,
152
- }
153
- }
154
- }
155
-
156
- for err in & errors {
157
- extra. warnings . custom_warning ( err. to_string ( ) ) ;
158
- }
159
-
160
- extra. warnings . on_fallback_ser :: < S > ( self . get_name ( ) , value, extra) ?;
161
- infer_serialize ( value, serializer, include, exclude, extra)
162
152
}
163
153
164
- fn get_name ( & self ) -> & str {
165
- & self . name
154
+ for err in & errors {
155
+ extra . warnings . custom_warning ( err . to_string ( ) ) ;
166
156
}
167
157
168
- fn retry_with_lax_check ( & self ) -> bool {
169
- self . choices . iter ( ) . any ( CombinedSerializer :: retry_with_lax_check)
170
- }
158
+ extra. warnings . on_fallback_py ( name, key, extra) ?;
159
+ infer_json_key ( key, extra)
171
160
}
172
161
173
- fn to_python (
162
+ fn serde_serialize < S : serde :: ser :: Serializer > (
174
163
value : & Bound < ' _ , PyAny > ,
164
+ serializer : S ,
175
165
include : Option < & Bound < ' _ , PyAny > > ,
176
166
exclude : Option < & Bound < ' _ , PyAny > > ,
177
167
extra : & Extra ,
178
168
choices : & [ CombinedSerializer ] ,
179
169
name : & str ,
180
- ) -> PyResult < PyObject > {
181
- // try the serializers in left to right order with error_on fallback=true
170
+ retry_with_lax_check : bool ,
171
+ ) -> Result < S :: Ok , S :: Error > {
172
+ let py = value. py ( ) ;
182
173
let mut new_extra = extra. clone ( ) ;
183
174
new_extra. check = SerCheck :: Strict ;
184
175
let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
185
176
186
177
for comb_serializer in choices. clone ( ) {
187
178
match comb_serializer. to_python ( value, include, exclude, & new_extra) {
188
- Ok ( v) => return Ok ( v ) ,
189
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value . py ( ) ) {
179
+ Ok ( v) => return infer_serialize ( v . bind ( py ) , serializer , None , None , extra ) ,
180
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py ) {
190
181
true => ( ) ,
191
182
false => errors. push ( err) ,
192
183
} ,
193
184
}
194
185
}
195
186
196
- let retry_with_lax_check = choices. clone ( ) . into_iter ( ) . any ( CombinedSerializer :: retry_with_lax_check) ;
197
187
if retry_with_lax_check {
198
188
new_extra. check = SerCheck :: Lax ;
199
189
for comb_serializer in choices {
200
190
match comb_serializer. to_python ( value, include, exclude, & new_extra) {
201
- Ok ( v) => return Ok ( v ) ,
202
- Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value . py ( ) ) {
191
+ Ok ( v) => return infer_serialize ( v . bind ( py ) , serializer , None , None , extra ) ,
192
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py ) {
203
193
true => ( ) ,
204
194
false => errors. push ( err) ,
205
195
} ,
@@ -211,8 +201,60 @@ fn to_python(
211
201
extra. warnings . custom_warning ( err. to_string ( ) ) ;
212
202
}
213
203
214
- extra. warnings . on_fallback_py ( name, value, extra) ?;
215
- infer_to_python ( value, include, exclude, extra)
204
+ extra. warnings . on_fallback_ser :: < S > ( name, value, extra) ?;
205
+ infer_serialize ( value, serializer, include, exclude, extra)
206
+ }
207
+
208
+ impl TypeSerializer for UnionSerializer {
209
+ fn to_python (
210
+ & self ,
211
+ value : & Bound < ' _ , PyAny > ,
212
+ include : Option < & Bound < ' _ , PyAny > > ,
213
+ exclude : Option < & Bound < ' _ , PyAny > > ,
214
+ extra : & Extra ,
215
+ ) -> PyResult < PyObject > {
216
+ to_python (
217
+ value,
218
+ include,
219
+ exclude,
220
+ extra,
221
+ & self . choices ,
222
+ self . get_name ( ) ,
223
+ self . retry_with_lax_check ( ) ,
224
+ )
225
+ }
226
+
227
+ fn json_key < ' a > ( & self , key : & ' a Bound < ' _ , PyAny > , extra : & Extra ) -> PyResult < Cow < ' a , str > > {
228
+ json_key ( key, extra, & self . choices , self . get_name ( ) , self . retry_with_lax_check ( ) )
229
+ }
230
+
231
+ fn serde_serialize < S : serde:: ser:: Serializer > (
232
+ & self ,
233
+ value : & Bound < ' _ , PyAny > ,
234
+ serializer : S ,
235
+ include : Option < & Bound < ' _ , PyAny > > ,
236
+ exclude : Option < & Bound < ' _ , PyAny > > ,
237
+ extra : & Extra ,
238
+ ) -> Result < S :: Ok , S :: Error > {
239
+ serde_serialize (
240
+ value,
241
+ serializer,
242
+ include,
243
+ exclude,
244
+ extra,
245
+ & self . choices ,
246
+ self . get_name ( ) ,
247
+ self . retry_with_lax_check ( ) ,
248
+ )
249
+ }
250
+
251
+ fn get_name ( & self ) -> & str {
252
+ & self . name
253
+ }
254
+
255
+ fn retry_with_lax_check ( & self ) -> bool {
256
+ self . choices . iter ( ) . any ( CombinedSerializer :: retry_with_lax_check)
257
+ }
216
258
}
217
259
218
260
#[ derive( Debug ) ]
@@ -294,7 +336,15 @@ impl TypeSerializer for TaggedUnionSerializer {
294
336
}
295
337
}
296
338
297
- to_python ( value, include, exclude, extra, & self . choices , self . get_name ( ) )
339
+ to_python (
340
+ value,
341
+ include,
342
+ exclude,
343
+ extra,
344
+ & self . choices ,
345
+ self . get_name ( ) ,
346
+ self . retry_with_lax_check ( ) ,
347
+ )
298
348
}
299
349
300
350
fn json_key < ' a > ( & self , key : & ' a Bound < ' _ , PyAny > , extra : & Extra ) -> PyResult < Cow < ' a , str > > {
@@ -316,13 +366,7 @@ impl TypeSerializer for TaggedUnionSerializer {
316
366
}
317
367
}
318
368
319
- let basic_union_ser = UnionSerializer :: from_choices ( self . choices . clone ( ) ) ;
320
- if let Ok ( s) = basic_union_ser {
321
- return s. json_key ( key, extra) ;
322
- }
323
-
324
- extra. warnings . on_fallback_py ( self . get_name ( ) , key, extra) ?;
325
- infer_json_key ( key, extra)
369
+ json_key ( key, extra, & self . choices , self . get_name ( ) , self . retry_with_lax_check ( ) )
326
370
}
327
371
328
372
fn serde_serialize < S : serde:: ser:: Serializer > (
@@ -355,13 +399,16 @@ impl TypeSerializer for TaggedUnionSerializer {
355
399
}
356
400
}
357
401
358
- let basic_union_ser = UnionSerializer :: from_choices ( self . choices . clone ( ) ) ;
359
- if let Ok ( s) = basic_union_ser {
360
- return s. serde_serialize ( value, serializer, include, exclude, extra) ;
361
- }
362
-
363
- extra. warnings . on_fallback_ser :: < S > ( self . get_name ( ) , value, extra) ?;
364
- infer_serialize ( value, serializer, include, exclude, extra)
402
+ serde_serialize (
403
+ value,
404
+ serializer,
405
+ include,
406
+ exclude,
407
+ extra,
408
+ & self . choices ,
409
+ self . get_name ( ) ,
410
+ self . retry_with_lax_check ( ) ,
411
+ )
365
412
}
366
413
367
414
fn get_name ( & self ) -> & str {
@@ -376,18 +423,16 @@ impl TypeSerializer for TaggedUnionSerializer {
376
423
impl TaggedUnionSerializer {
377
424
fn get_discriminator_value ( & self , value : & Bound < ' _ , PyAny > ) -> Option < Py < PyAny > > {
378
425
let py = value. py ( ) ;
379
- match & self . discriminator {
426
+ let discriminator_value = match & self . discriminator {
380
427
Discriminator :: LookupKey ( lookup_key) => match lookup_key {
381
428
LookupKey :: Simple { py_key, .. } => value. getattr ( py_key) . ok ( ) . map ( |obj| obj. to_object ( py) ) ,
382
429
_ => None ,
383
430
} ,
384
- Discriminator :: Function ( func) => func. call1 ( py, ( value, ) ) . ok ( ) . or_else ( || {
385
- // Try converting object to a dict, might be more compatible with poorly defined callable discriminator
386
- value
387
- . call_method0 ( intern ! ( py, "dict" ) )
388
- . and_then ( |v| func. call1 ( py, ( v. to_object ( py) , ) ) )
389
- . ok ( )
390
- } ) ,
431
+ Discriminator :: Function ( func) => func. call1 ( py, ( value, ) ) . ok ( ) ,
432
+ } ;
433
+ if discriminator_value. is_none ( ) {
434
+ // warn if the discriminator value is not found
391
435
}
436
+ return discriminator_value;
392
437
}
393
438
}
0 commit comments