@@ -86,7 +86,7 @@ fn to_python(
86
86
new_extra. check = SerCheck :: Strict ;
87
87
let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
88
88
89
- for comb_serializer in choices. clone ( ) {
89
+ for comb_serializer in choices {
90
90
match comb_serializer. to_python ( value, include, exclude, & new_extra) {
91
91
Ok ( v) => return Ok ( v) ,
92
92
Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( value. py ( ) ) {
@@ -117,18 +117,18 @@ fn to_python(
117
117
infer_to_python ( value, include, exclude, extra)
118
118
}
119
119
120
- fn json_key (
121
- key : & Bound < ' _ , PyAny > ,
120
+ fn json_key < ' a > (
121
+ key : & ' a Bound < ' _ , PyAny > ,
122
122
extra : & Extra ,
123
123
choices : & [ CombinedSerializer ] ,
124
124
name : & str ,
125
125
retry_with_lax_check : bool ,
126
- ) -> PyResult < Cow < str > > {
126
+ ) -> PyResult < Cow < ' a , str > > {
127
127
let mut new_extra = extra. clone ( ) ;
128
128
new_extra. check = SerCheck :: Strict ;
129
129
let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
130
130
131
- for comb_serializer in choices. clone ( ) {
131
+ for comb_serializer in choices {
132
132
match comb_serializer. json_key ( key, & new_extra) {
133
133
Ok ( v) => return Ok ( v) ,
134
134
Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( key. py ( ) ) {
@@ -159,6 +159,7 @@ fn json_key(
159
159
infer_json_key ( key, extra)
160
160
}
161
161
162
+ #[ allow( clippy:: too_many_arguments) ]
162
163
fn serde_serialize < S : serde:: ser:: Serializer > (
163
164
value : & Bound < ' _ , PyAny > ,
164
165
serializer : S ,
@@ -174,7 +175,7 @@ fn serde_serialize<S: serde::ser::Serializer>(
174
175
new_extra. check = SerCheck :: Strict ;
175
176
let mut errors: SmallVec < [ PyErr ; SMALL_UNION_THRESHOLD ] > = SmallVec :: new ( ) ;
176
177
177
- for comb_serializer in choices. clone ( ) {
178
+ for comb_serializer in choices {
178
179
match comb_serializer. to_python ( value, include, exclude, & new_extra) {
179
180
Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
180
181
Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py) {
@@ -303,7 +304,7 @@ impl BuildSerializer for TaggedUnionSerializer {
303
304
}
304
305
}
305
306
306
- impl_py_gc_traverse ! ( TaggedUnionSerializer { discriminator, lookup } ) ;
307
+ impl_py_gc_traverse ! ( TaggedUnionSerializer { discriminator, choices } ) ;
307
308
308
309
impl TypeSerializer for TaggedUnionSerializer {
309
310
fn to_python (
@@ -318,16 +319,18 @@ impl TypeSerializer for TaggedUnionSerializer {
318
319
let mut new_extra = extra. clone ( ) ;
319
320
new_extra. check = SerCheck :: Strict ;
320
321
321
- if let Some ( tag) = self . get_discriminator_value ( value) {
322
+ if let Some ( tag) = self . get_discriminator_value ( value, extra ) {
322
323
let tag_str = tag. to_string ( ) ;
323
- if let Some ( serializer) = self . lookup . get ( & tag_str) {
324
- match self . choices [ * serializer] . to_python ( value, include, exclude, & new_extra) {
324
+ if let Some ( & serializer_index) = self . lookup . get ( & tag_str) {
325
+ let serializer = & self . choices [ serializer_index] ;
326
+
327
+ match serializer. to_python ( value, include, exclude, & new_extra) {
325
328
Ok ( v) => return Ok ( v) ,
326
329
Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py) {
327
330
true => {
328
331
if self . retry_with_lax_check ( ) {
329
332
new_extra. check = SerCheck :: Lax ;
330
- return self . choices [ * serializer] . to_python ( value, include, exclude, & new_extra) ;
333
+ return serializer. to_python ( value, include, exclude, & new_extra) ;
331
334
}
332
335
}
333
336
false => return Err ( err) ,
@@ -348,20 +351,26 @@ impl TypeSerializer for TaggedUnionSerializer {
348
351
}
349
352
350
353
fn json_key < ' a > ( & self , key : & ' a Bound < ' _ , PyAny > , extra : & Extra ) -> PyResult < Cow < ' a , str > > {
354
+ let py = key. py ( ) ;
351
355
let mut new_extra = extra. clone ( ) ;
352
356
new_extra. check = SerCheck :: Strict ;
353
357
354
- if let Some ( tag) = self . get_discriminator_value ( key) {
358
+ if let Some ( tag) = self . get_discriminator_value ( key, extra ) {
355
359
let tag_str = tag. to_string ( ) ;
356
- if let Some ( serializer) = self . lookup . get ( & tag_str) {
357
- match self . choices [ * serializer] . json_key ( key, & new_extra) {
360
+ if let Some ( & serializer_index) = self . lookup . get ( & tag_str) {
361
+ let serializer = & self . choices [ serializer_index] ;
362
+
363
+ match serializer. json_key ( key, & new_extra) {
358
364
Ok ( v) => return Ok ( v) ,
359
- Err ( _) => {
360
- if self . retry_with_lax_check ( ) {
361
- new_extra. check = SerCheck :: Lax ;
362
- return self . choices [ * serializer] . json_key ( key, & new_extra) ;
365
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py) {
366
+ true => {
367
+ if self . retry_with_lax_check ( ) {
368
+ new_extra. check = SerCheck :: Lax ;
369
+ return serializer. json_key ( key, & new_extra) ;
370
+ }
363
371
}
364
- }
372
+ false => return Err ( err) ,
373
+ } ,
365
374
}
366
375
}
367
376
}
@@ -381,20 +390,25 @@ impl TypeSerializer for TaggedUnionSerializer {
381
390
let mut new_extra = extra. clone ( ) ;
382
391
new_extra. check = SerCheck :: Strict ;
383
392
384
- if let Some ( tag) = self . get_discriminator_value ( value) {
393
+ if let Some ( tag) = self . get_discriminator_value ( value, extra ) {
385
394
let tag_str = tag. to_string ( ) ;
386
- if let Some ( selected_serializer) = self . lookup . get ( & tag_str) {
387
- match self . choices [ * selected_serializer] . to_python ( value, include, exclude, & new_extra) {
395
+ if let Some ( & serializer_index) = self . lookup . get ( & tag_str) {
396
+ let selected_serializer = & self . choices [ serializer_index] ;
397
+
398
+ match selected_serializer. to_python ( value, include, exclude, & new_extra) {
388
399
Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
389
- Err ( _) => {
390
- if self . retry_with_lax_check ( ) {
391
- new_extra. check = SerCheck :: Lax ;
392
- match self . choices [ * selected_serializer] . to_python ( value, include, exclude, & new_extra) {
393
- Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
394
- Err ( err) => return Err ( py_err_se_err ( err) ) ,
400
+ Err ( err) => match err. is_instance_of :: < PydanticSerializationUnexpectedValue > ( py) {
401
+ true => {
402
+ if self . retry_with_lax_check ( ) {
403
+ new_extra. check = SerCheck :: Lax ;
404
+ match selected_serializer. to_python ( value, include, exclude, & new_extra) {
405
+ Ok ( v) => return infer_serialize ( v. bind ( py) , serializer, None , None , extra) ,
406
+ Err ( err) => return Err ( py_err_se_err ( err) ) ,
407
+ }
395
408
}
396
409
}
397
- }
410
+ false => return Err ( py_err_se_err ( err) ) ,
411
+ } ,
398
412
}
399
413
}
400
414
}
@@ -421,7 +435,7 @@ impl TypeSerializer for TaggedUnionSerializer {
421
435
}
422
436
423
437
impl TaggedUnionSerializer {
424
- fn get_discriminator_value ( & self , value : & Bound < ' _ , PyAny > ) -> Option < Py < PyAny > > {
438
+ fn get_discriminator_value ( & self , value : & Bound < ' _ , PyAny > , extra : & Extra ) -> Option < Py < PyAny > > {
425
439
let py = value. py ( ) ;
426
440
let discriminator_value = match & self . discriminator {
427
441
Discriminator :: LookupKey ( lookup_key) => match lookup_key {
@@ -431,8 +445,12 @@ impl TaggedUnionSerializer {
431
445
Discriminator :: Function ( func) => func. call1 ( py, ( value, ) ) . ok ( ) ,
432
446
} ;
433
447
if discriminator_value. is_none ( ) {
434
- // warn if the discriminator value is not found
448
+ extra. warnings . custom_warning (
449
+ format ! (
450
+ "Failed to get discriminator value for tagged union serialization for {value} - defaulting to left to right union serialization."
451
+ )
452
+ ) ;
435
453
}
436
- return discriminator_value;
454
+ discriminator_value
437
455
}
438
456
}
0 commit comments