Skip to content

Commit 7f2b1da

Browse files
committed
missing lifteime and pygctraverse stuff
1 parent dacb9ff commit 7f2b1da

File tree

1 file changed

+153
-108
lines changed
  • src/serializers/type_serializers

1 file changed

+153
-108
lines changed

src/serializers/type_serializers/union.rs

Lines changed: 153 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -72,134 +72,124 @@ impl UnionSerializer {
7272

7373
impl_py_gc_traverse!(UnionSerializer { choices });
7474

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();
8588

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+
}
9098

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) {
93103
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()) {
95105
true => (),
96106
false => errors.push(err),
97107
},
98108
}
99109
}
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+
}
116111

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());
119114
}
120115

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+
}
133119

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()) {
138147
true => (),
139148
false => errors.push(err),
140149
},
141150
}
142151
}
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)
162152
}
163153

164-
fn get_name(&self) -> &str {
165-
&self.name
154+
for err in &errors {
155+
extra.warnings.custom_warning(err.to_string());
166156
}
167157

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)
171160
}
172161

173-
fn to_python(
162+
fn serde_serialize<S: serde::ser::Serializer>(
174163
value: &Bound<'_, PyAny>,
164+
serializer: S,
175165
include: Option<&Bound<'_, PyAny>>,
176166
exclude: Option<&Bound<'_, PyAny>>,
177167
extra: &Extra,
178168
choices: &[CombinedSerializer],
179169
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();
182173
let mut new_extra = extra.clone();
183174
new_extra.check = SerCheck::Strict;
184175
let mut errors: SmallVec<[PyErr; SMALL_UNION_THRESHOLD]> = SmallVec::new();
185176

186177
for comb_serializer in choices.clone() {
187178
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) {
190181
true => (),
191182
false => errors.push(err),
192183
},
193184
}
194185
}
195186

196-
let retry_with_lax_check = choices.clone().into_iter().any(CombinedSerializer::retry_with_lax_check);
197187
if retry_with_lax_check {
198188
new_extra.check = SerCheck::Lax;
199189
for comb_serializer in choices {
200190
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) {
203193
true => (),
204194
false => errors.push(err),
205195
},
@@ -211,8 +201,60 @@ fn to_python(
211201
extra.warnings.custom_warning(err.to_string());
212202
}
213203

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+
}
216258
}
217259

218260
#[derive(Debug)]
@@ -294,7 +336,15 @@ impl TypeSerializer for TaggedUnionSerializer {
294336
}
295337
}
296338

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+
)
298348
}
299349

300350
fn json_key<'a>(&self, key: &'a Bound<'_, PyAny>, extra: &Extra) -> PyResult<Cow<'a, str>> {
@@ -316,13 +366,7 @@ impl TypeSerializer for TaggedUnionSerializer {
316366
}
317367
}
318368

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())
326370
}
327371

328372
fn serde_serialize<S: serde::ser::Serializer>(
@@ -355,13 +399,16 @@ impl TypeSerializer for TaggedUnionSerializer {
355399
}
356400
}
357401

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+
)
365412
}
366413

367414
fn get_name(&self) -> &str {
@@ -376,18 +423,16 @@ impl TypeSerializer for TaggedUnionSerializer {
376423
impl TaggedUnionSerializer {
377424
fn get_discriminator_value(&self, value: &Bound<'_, PyAny>) -> Option<Py<PyAny>> {
378425
let py = value.py();
379-
match &self.discriminator {
426+
let discriminator_value = match &self.discriminator {
380427
Discriminator::LookupKey(lookup_key) => match lookup_key {
381428
LookupKey::Simple { py_key, .. } => value.getattr(py_key).ok().map(|obj| obj.to_object(py)),
382429
_ => None,
383430
},
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
391435
}
436+
return discriminator_value;
392437
}
393438
}

0 commit comments

Comments
 (0)