Skip to content

Commit 00a9aaf

Browse files
committed
fix for python 3.11
1 parent 50d3e24 commit 00a9aaf

File tree

7 files changed

+26
-32
lines changed

7 files changed

+26
-32
lines changed

src/input/input_abstract.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::fmt;
22

3-
use pyo3::types::{PyDict, PyString, PyType};
3+
use pyo3::types::{PyDict, PyType};
44
use pyo3::{intern, prelude::*};
55

66
use crate::errors::{InputValue, LocItem, ValResult};
@@ -40,11 +40,6 @@ pub trait Input<'a>: fmt::Debug + ToPyObject {
4040

4141
fn is_none(&self) -> bool;
4242

43-
#[cfg_attr(has_no_coverage, no_coverage)]
44-
fn input_get_attr(&self, _name: &PyString) -> Option<PyResult<&PyAny>> {
45-
None
46-
}
47-
4843
fn input_is_instance(&self, _class: &PyType) -> Option<&PyAny> {
4944
None
5045
}

src/input/input_python.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,6 @@ impl<'a> Input<'a> for PyAny {
109109
self.is_none()
110110
}
111111

112-
fn input_get_attr(&self, name: &PyString) -> Option<PyResult<&PyAny>> {
113-
Some(self.getattr(name))
114-
}
115-
116112
fn input_is_instance(&self, class: &PyType) -> Option<&PyAny> {
117113
if self.is_instance(class).unwrap_or(false) {
118114
Some(self)

src/serializers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use config::SerializationConfig;
1111
pub use errors::{PydanticSerializationError, PydanticSerializationUnexpectedValue};
1212
use extra::{CollectWarnings, SerRecursionGuard};
1313
pub(crate) use extra::{Extra, SerMode, SerializationState};
14+
pub(crate) use shared::slots_dc_dict;
1415
pub use shared::CombinedSerializer;
1516
use shared::{to_json_bytes, BuildSerializer, TypeSerializer};
1617

src/serializers/shared.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt::Debug;
33

44
use pyo3::exceptions::PyTypeError;
55
use pyo3::prelude::*;
6-
use pyo3::types::{PyDict, PySet, PyString, PyTuple};
6+
use pyo3::types::{PyDict, PySet, PyString};
77
use pyo3::{intern, PyTraverseError, PyVisit};
88

99
use enum_dispatch::enum_dispatch;
@@ -331,16 +331,9 @@ pub(super) fn object_to_dict<'py>(value: &'py PyAny, is_model: bool, extra: &Ext
331331
let py = value.py();
332332
let attrs: &PyDict = match value.getattr(intern!(py, "__dict__")) {
333333
Ok(attr) => attr.downcast()?,
334-
Err(_) => {
335-
let slots: &PyTuple = value.getattr(intern!(py, "__slots__"))?.downcast()?;
336-
let dict = PyDict::new(py);
337-
for slot in slots {
338-
let slot: &PyString = slot.downcast()?;
339-
dict.set_item(slot, value.getattr(slot)?)?;
340-
}
341-
dict
342-
}
334+
Err(_) => return slots_dc_dict(value),
343335
};
336+
344337
if is_model && extra.exclude_unset {
345338
let fields_set: &PySet = value.getattr(intern!(py, "__pydantic_fields_set__"))?.downcast()?;
346339

@@ -355,3 +348,14 @@ pub(super) fn object_to_dict<'py>(value: &'py PyAny, is_model: bool, extra: &Ext
355348
Ok(attrs)
356349
}
357350
}
351+
352+
pub(crate) fn slots_dc_dict(value: &PyAny) -> PyResult<&PyDict> {
353+
let py = value.py();
354+
let dc_fields: &PyDict = value.getattr(intern!(py, "__dataclass_fields__"))?.downcast()?;
355+
let dict = PyDict::new(py);
356+
for field in dc_fields.keys() {
357+
let field: &PyString = field.downcast()?;
358+
dict.set_item(field, value.getattr(field)?)?;
359+
}
360+
Ok(dict)
361+
}

src/validators/dataclass.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::errors::{ErrorType, ValError, ValLineError, ValResult};
1010
use crate::input::{GenericArguments, Input};
1111
use crate::lookup_key::LookupKey;
1212
use crate::recursion_guard::RecursionGuard;
13+
use crate::serializers::slots_dc_dict;
1314
use crate::validators::function::convert_err;
1415

1516
use super::arguments::{json_get, json_slice, py_get, py_slice};
@@ -490,17 +491,7 @@ impl Validator for DataclassValidator {
490491
if self.revalidate.should_revalidate(py_input, class) {
491492
let input_dict = match py_input.getattr(intern!(py, "__dict__")) {
492493
Ok(attr) => attr,
493-
Err(_) => {
494-
// we inspect `__slots__` to get the attributes instead of using `self.slots` as a
495-
// subclass could have `slots=True`
496-
let slots: &PyTuple = py_input.getattr(intern!(py, "__slots__"))?.downcast()?;
497-
let dict = PyDict::new(py);
498-
for slot in slots {
499-
let slot: &PyString = slot.downcast()?;
500-
dict.set_item(slot, py_input.getattr(slot)?)?;
501-
}
502-
dict
503-
}
494+
Err(_) => slots_dc_dict(py_input)?,
504495
};
505496
let val_output = self
506497
.validator

src/validators/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl Validator for ModelValidator {
211211

212212
let (output, _, updated_fields_set): (&PyDict, &PyAny, &PySet) = output.extract(py)?;
213213

214-
if let Ok(fields_set) = model.input_get_attr(intern!(py, DUNDER_FIELDS_SET_KEY)).unwrap() {
214+
if let Ok(fields_set) = model.getattr(intern!(py, DUNDER_FIELDS_SET_KEY)) {
215215
let fields_set: &PySet = fields_set.downcast()?;
216216
for field_name in updated_fields_set {
217217
fields_set.add(field_name)?;

tests/serializers/test_any.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,3 +484,10 @@ class Foo:
484484

485485
foo = Foo(1, 'a')
486486
assert any_serializer.to_python(foo) == IsStrictDict(a=1, b='a')
487+
488+
@dataclasses.dataclass(slots=True)
489+
class Foo2(Foo):
490+
pass
491+
492+
foo2 = Foo2(2, 'b')
493+
assert any_serializer.to_python(foo2) == IsStrictDict(a=2, b='b')

0 commit comments

Comments
 (0)