Skip to content

Commit 72732b0

Browse files
committed
update serializers to use Py2
1 parent d9227db commit 72732b0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+730
-662
lines changed

src/errors/validation_exception.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,13 +636,13 @@ impl<'py> Serialize for PyLineErrorSerializer<'py> {
636636
if self.include_input {
637637
map.serialize_entry(
638638
"input",
639-
&self.extra.serialize_infer(self.line_error.input_value.as_ref(py)),
639+
&self.extra.serialize_infer(self.line_error.input_value.attach(py)),
640640
)?;
641641
}
642642

643643
if self.include_context {
644644
if let Some(context) = self.line_error.error_type.py_dict(py).map_err(py_err_json::<S>)? {
645-
map.serialize_entry("ctx", &self.extra.serialize_infer(context.as_ref(py)))?;
645+
map.serialize_entry("ctx", &self.extra.serialize_infer(context.attach(py)))?;
646646
}
647647
}
648648
if let Some(url_prefix) = self.url_prefix {

src/input/input_abstract.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub trait Input<'a>: fmt::Debug + ToPyObject + AsLocItem + Sized {
6565
false
6666
}
6767

68-
fn as_kwargs(&'a self, py: Python<'a>) -> Option<&'a PyDict>;
68+
fn as_kwargs(&self, py: Python<'a>) -> Option<Py2<'a, PyDict>>;
6969

7070
fn input_is_subclass(&self, _class: &PyType) -> PyResult<bool> {
7171
Ok(false)

src/input/input_json.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ impl<'a> Input<'a> for JsonValue {
4747
matches!(self, JsonValue::Null)
4848
}
4949

50-
fn as_kwargs(&'a self, py: Python<'a>) -> Option<&'a PyDict> {
50+
fn as_kwargs(&self, py: Python<'a>) -> Option<Py2<'a, PyDict>> {
5151
match self {
5252
JsonValue::Object(object) => {
53-
let dict = PyDict::new(py);
53+
let dict = PyDict::new2(py);
5454
for (k, v) in object.iter() {
5555
dict.set_item(k, v.to_object(py)).unwrap();
5656
}
@@ -339,7 +339,7 @@ impl<'a> Input<'a> for String {
339339
InputValue::Json(JsonValue::Str(self.clone()))
340340
}
341341

342-
fn as_kwargs(&'a self, _py: Python<'a>) -> Option<&'a PyDict> {
342+
fn as_kwargs(&self, _py: Python<'a>) -> Option<Py2<'a, PyDict>> {
343343
None
344344
}
345345

src/input/input_python.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ impl<'a> Input<'a> for Py2<'a, PyAny> {
117117
true
118118
}
119119

120-
fn as_kwargs(&'a self, _py: Python<'a>) -> Option<&'a PyDict> {
121-
self.downcast::<PyDict>().ok().map(|dict| dict.clone().into_gil_ref())
120+
fn as_kwargs(&self, _py: Python<'a>) -> Option<Py2<'a, PyDict>> {
121+
self.downcast::<PyDict>().ok().map(Clone::clone)
122122
}
123123

124124
fn input_is_subclass(&self, class: &PyType) -> PyResult<bool> {
@@ -429,14 +429,11 @@ impl<'a> Input<'a> for Py2<'a, PyAny> {
429429
}
430430
}
431431

432-
if from_attributes_applicable(self.as_gil_ref()) {
432+
if from_attributes_applicable(self) {
433433
Ok(self.clone().into())
434-
} else if let Ok((obj, kwargs)) = self.clone().into_gil_ref().extract::<(&PyAny, &PyDict)>() {
435-
if from_attributes_applicable(obj) {
436-
Ok(GenericMapping::PyGetAttr(
437-
Py2::borrowed_from_gil_ref(&obj).clone(),
438-
Some(Py2::borrowed_from_gil_ref(&kwargs).clone()),
439-
))
434+
} else if let Ok((obj, kwargs)) = self.extract() {
435+
if from_attributes_applicable(&obj) {
436+
Ok(GenericMapping::PyGetAttr(obj, Some(kwargs)))
440437
} else {
441438
Err(ValError::new(ErrorTypeDefaults::ModelAttributesType, self))
442439
}
@@ -735,19 +732,20 @@ impl BorrowInput for Py2Borrowed<'_, '_, PyAny> {
735732

736733
/// Best effort check of whether it's likely to make sense to inspect obj for attributes and iterate over it
737734
/// with `obj.dir()`
738-
fn from_attributes_applicable(obj: &PyAny) -> bool {
739-
let module_name = match obj.get_type().getattr(intern!(obj.py(), "__module__")) {
740-
Ok(module) => match module.extract::<&str>() {
741-
Ok(s) => s,
742-
Err(_) => return false,
743-
},
744-
Err(_) => return false,
735+
fn from_attributes_applicable(obj: &Py2<'_, PyAny>) -> bool {
736+
let Some(module_name) = obj
737+
.get_type()
738+
.getattr(intern!(obj.py(), "__module__"))
739+
.ok()
740+
.and_then(|module_name| module_name.downcast_into::<PyString>().ok())
741+
else {
742+
return false;
745743
};
746744
// I don't think it's a very good list at all! But it doesn't have to be at perfect, it just needs to avoid
747745
// the most egregious foot guns, it's mostly just to catch "builtins"
748746
// still happy to add more or do something completely different if anyone has a better idea???
749747
// dbg!(obj, module_name);
750-
!matches!(module_name, "builtins" | "datetime" | "collections")
748+
!matches!(module_name.to_str(), Ok("builtins" | "datetime" | "collections"))
751749
}
752750

753751
/// Utility for extracting a string from a PyAny, if possible.

src/input/input_string.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl<'a> Input<'a> for StringMapping<'a> {
6969
}
7070
}
7171

72-
fn as_kwargs(&'a self, _py: Python<'a>) -> Option<&'a PyDict> {
72+
fn as_kwargs(&self, _py: Python<'a>) -> Option<Py2<'a, PyDict>> {
7373
None
7474
}
7575

src/input/return_enums.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ impl<'py> Iterator for MappingGenericIterator<'py> {
513513

514514
fn next(&mut self) -> Option<Self::Item> {
515515
Some(match self.iter.next()? {
516-
Ok(item) => item.into_gil_ref().extract().map_err(|_| {
516+
Ok(item) => item.extract().map_err(|_| {
517517
ValError::new(
518518
ErrorType::MappingType {
519519
error: MAPPING_TUPLE_ERROR.into(),

src/input/shared.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,6 @@ pub fn decimal_as_int<'a>(input: &'a impl Input<'a>, decimal: &Py2<'a, PyAny>) -
149149
}
150150
let (numerator, denominator) = decimal
151151
.call_method0(intern!(py, "as_integer_ratio"))?
152-
.into_gil_ref()
153152
.extract::<(Py2<'_, PyAny>, Py2<'_, PyAny>)>()?;
154153
if denominator.extract::<i64>().map_or(true, |d| d != 1) {
155154
return Err(ValError::new(ErrorTypeDefaults::IntFromFloat, input));

src/serializers/computed_fields.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ impl ComputedFields {
4141

4242
pub fn to_python(
4343
&self,
44-
model: &PyAny,
44+
model: &Py2<'_, PyAny>,
4545
output_dict: &PyDict,
4646
filter: &SchemaFilter<isize>,
47-
include: Option<&PyAny>,
48-
exclude: Option<&PyAny>,
47+
include: Option<&Py2<'_, PyAny>>,
48+
exclude: Option<&Py2<'_, PyAny>>,
4949
extra: &Extra,
5050
) -> PyResult<()> {
5151
if extra.round_trip {
@@ -60,28 +60,28 @@ impl ComputedFields {
6060

6161
pub fn serde_serialize<S: serde::ser::Serializer>(
6262
&self,
63-
model: &PyAny,
63+
model: &Py2<'_, PyAny>,
6464
map: &mut S::SerializeMap,
6565
filter: &SchemaFilter<isize>,
66-
include: Option<&PyAny>,
67-
exclude: Option<&PyAny>,
66+
include: Option<&Py2<'_, PyAny>>,
67+
exclude: Option<&Py2<'_, PyAny>>,
6868
extra: &Extra,
6969
) -> Result<(), S::Error> {
7070
if extra.round_trip {
7171
// Do not serialize computed fields
7272
return Ok(());
7373
}
7474
for computed_field in &self.0 {
75-
let property_name_py = computed_field.property_name_py.as_ref(model.py());
75+
let property_name_py = computed_field.property_name_py.attach(model.py());
7676
if let Some((next_include, next_exclude)) = filter
7777
.key_filter(property_name_py, include, exclude)
7878
.map_err(py_err_se_err)?
7979
{
8080
let cfs = ComputedFieldSerializer {
8181
model,
8282
computed_field,
83-
include: next_include,
84-
exclude: next_exclude,
83+
include: next_include.as_ref(),
84+
exclude: next_exclude.as_ref(),
8585
extra,
8686
};
8787
let key = match extra.by_alias {
@@ -130,27 +130,27 @@ impl ComputedField {
130130

131131
fn to_python(
132132
&self,
133-
model: &PyAny,
133+
model: &Py2<'_, PyAny>,
134134
output_dict: &PyDict,
135135
filter: &SchemaFilter<isize>,
136-
include: Option<&PyAny>,
137-
exclude: Option<&PyAny>,
136+
include: Option<&Py2<'_, PyAny>>,
137+
exclude: Option<&Py2<'_, PyAny>>,
138138
extra: &Extra,
139139
) -> PyResult<()> {
140140
let py = model.py();
141-
let property_name_py = self.property_name_py.as_ref(py);
141+
let property_name_py = self.property_name_py.attach(py);
142142

143143
if let Some((next_include, next_exclude)) = filter.key_filter(property_name_py, include, exclude)? {
144144
let next_value = model.getattr(property_name_py)?;
145145

146146
let value = self
147147
.serializer
148-
.to_python(next_value, next_include, next_exclude, extra)?;
148+
.to_python(&next_value, next_include.as_ref(), next_exclude.as_ref(), extra)?;
149149
if extra.exclude_none && value.is_none(py) {
150150
return Ok(());
151151
}
152152
let key = match extra.by_alias {
153-
true => self.alias_py.as_ref(py),
153+
true => self.alias_py.attach(py),
154154
false => property_name_py,
155155
};
156156
output_dict.set_item(key, value)?;
@@ -160,10 +160,10 @@ impl ComputedField {
160160
}
161161

162162
pub(crate) struct ComputedFieldSerializer<'py> {
163-
model: &'py PyAny,
163+
model: &'py Py2<'py, PyAny>,
164164
computed_field: &'py ComputedField,
165-
include: Option<&'py PyAny>,
166-
exclude: Option<&'py PyAny>,
165+
include: Option<&'py Py2<'py, PyAny>>,
166+
exclude: Option<&'py Py2<'py, PyAny>>,
167167
extra: &'py Extra<'py>,
168168
}
169169

@@ -183,7 +183,7 @@ impl<'py> Serialize for ComputedFieldSerializer<'py> {
183183
let property_name_py = self.computed_field.property_name_py.as_ref(py);
184184
let next_value = self.model.getattr(property_name_py).map_err(py_err_se_err)?;
185185
let s = PydanticSerializer::new(
186-
next_value,
186+
&next_value,
187187
&self.computed_field.serializer,
188188
self.include,
189189
self.exclude,

src/serializers/extra.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl SerializationState {
4141
exclude_none: bool,
4242
round_trip: bool,
4343
serialize_unknown: bool,
44-
fallback: Option<&'py PyAny>,
44+
fallback: Option<&'py Py2<'py, PyAny>>,
4545
) -> Extra<'py> {
4646
Extra::new(
4747
py,
@@ -83,10 +83,10 @@ pub(crate) struct Extra<'a> {
8383
// data representing the current model field
8484
// that is being serialized, if this is a model serializer
8585
// it will be None otherwise
86-
pub model: Option<&'a PyAny>,
86+
pub model: Option<&'a Py2<'a, PyAny>>,
8787
pub field_name: Option<&'a str>,
8888
pub serialize_unknown: bool,
89-
pub fallback: Option<&'a PyAny>,
89+
pub fallback: Option<&'a Py2<'a, PyAny>>,
9090
}
9191

9292
impl<'a> Extra<'a> {
@@ -103,7 +103,7 @@ impl<'a> Extra<'a> {
103103
config: &'a SerializationConfig,
104104
rec_guard: &'a SerRecursionGuard,
105105
serialize_unknown: bool,
106-
fallback: Option<&'a PyAny>,
106+
fallback: Option<&'a Py2<'a, PyAny>>,
107107
) -> Self {
108108
Self {
109109
mode,
@@ -124,7 +124,7 @@ impl<'a> Extra<'a> {
124124
}
125125
}
126126

127-
pub fn serialize_infer<'py>(&'py self, value: &'py PyAny) -> super::infer::SerializeInfer<'py> {
127+
pub fn serialize_infer<'py>(&'py self, value: &'py Py2<'py, PyAny>) -> super::infer::SerializeInfer<'py> {
128128
super::infer::SerializeInfer::new(value, None, None, self)
129129
}
130130
}
@@ -178,10 +178,10 @@ impl ExtraOwned {
178178
config: extra.config.clone(),
179179
rec_guard: extra.rec_guard.clone(),
180180
check: extra.check,
181-
model: extra.model.map(Into::into),
181+
model: extra.model.map(|model| model.clone().into()),
182182
field_name: extra.field_name.map(ToString::to_string),
183183
serialize_unknown: extra.serialize_unknown,
184-
fallback: extra.fallback.map(Into::into),
184+
fallback: extra.fallback.map(|fallback| fallback.clone().into()),
185185
}
186186
}
187187

@@ -198,10 +198,10 @@ impl ExtraOwned {
198198
config: &self.config,
199199
rec_guard: &self.rec_guard,
200200
check: self.check,
201-
model: self.model.as_ref().map(|m| m.as_ref(py)),
201+
model: self.model.as_ref().map(|m| m.attach(py)),
202202
field_name: self.field_name.as_deref(),
203203
serialize_unknown: self.serialize_unknown,
204-
fallback: self.fallback.as_ref().map(|m| m.as_ref(py)),
204+
fallback: self.fallback.as_ref().map(|m| m.attach(py)),
205205
}
206206
}
207207
}
@@ -272,7 +272,7 @@ impl CollectWarnings {
272272
}
273273
}
274274

275-
pub fn on_fallback_py(&self, field_type: &str, value: &PyAny, extra: &Extra) -> PyResult<()> {
275+
pub fn on_fallback_py(&self, field_type: &str, value: &Py2<'_, PyAny>, extra: &Extra) -> PyResult<()> {
276276
// special case for None as it's very common e.g. as a default value
277277
if value.is_none() {
278278
Ok(())
@@ -287,7 +287,7 @@ impl CollectWarnings {
287287
pub fn on_fallback_ser<S: serde::ser::Serializer>(
288288
&self,
289289
field_type: &str,
290-
value: &PyAny,
290+
value: &Py2<'_, PyAny>,
291291
extra: &Extra,
292292
) -> Result<(), S::Error> {
293293
// special case for None as it's very common e.g. as a default value
@@ -304,9 +304,13 @@ impl CollectWarnings {
304304
}
305305
}
306306

307-
fn fallback_warning(&self, field_type: &str, value: &PyAny) {
307+
fn fallback_warning(&self, field_type: &str, value: &Py2<'_, PyAny>) {
308308
if self.active {
309-
let type_name = value.get_type().name().unwrap_or("<unknown python object>");
309+
let type_name = value.get_type().name().ok();
310+
let type_name = type_name
311+
.as_ref()
312+
.and_then(|s| s.to_str().ok())
313+
.unwrap_or("<unknown python object>");
310314
self.add_warning(format!(
311315
"Expected `{field_type}` but got `{type_name}` - serialized value may not be as expected"
312316
));
@@ -345,7 +349,7 @@ pub struct SerRecursionGuard {
345349
}
346350

347351
impl SerRecursionGuard {
348-
pub fn add(&self, value: &PyAny, def_ref_id: usize) -> PyResult<usize> {
352+
pub fn add(&self, value: &Py2<'_, PyAny>, def_ref_id: usize) -> PyResult<usize> {
349353
// https://doc.rust-lang.org/std/collections/struct.HashSet.html#method.insert
350354
// "If the set did not have this value present, `true` is returned."
351355
let id = value.as_ptr() as usize;

0 commit comments

Comments
 (0)