Skip to content

Commit 717c0c4

Browse files
authored
Merge pull request #27 from Jij-Inc/pr/LockedThread/22
Minor revise of #22
2 parents 9512d39 + 53c6dcb commit 717c0c4

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

src/de.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,20 @@ impl<'de> de::Deserializer<'de> for PyAnyDeserializer<'_> {
328328
if self.0.is_instance_of::<PyFloat>() {
329329
return visitor.visit_f64(self.0.extract()?);
330330
}
331+
if self.0.hasattr("__dict__")? {
332+
return visitor.visit_map(MapDeserializer::new(
333+
self.0.getattr("__dict__")?.downcast()?,
334+
));
335+
}
336+
if self.0.hasattr("__slots__")? {
337+
// __slots__ and __dict__ are mutually exclusive, see
338+
// https://docs.python.org/3/reference/datamodel.html#slots
339+
return visitor.visit_map(MapDeserializer::from_slots(&self.0)?);
340+
}
331341
if self.0.is_none() {
332342
return visitor.visit_none();
333343
}
344+
334345
unreachable!("Unsupported type: {}", self.0.get_type());
335346
}
336347

@@ -498,6 +509,18 @@ impl<'py> MapDeserializer<'py> {
498509
}
499510
Self { keys, values }
500511
}
512+
513+
fn from_slots(obj: &Bound<'py, PyAny>) -> Result<Self> {
514+
let mut keys = vec![];
515+
let mut values = vec![];
516+
for key in obj.getattr("__slots__")?.try_iter()? {
517+
let key = key?;
518+
keys.push(key.clone());
519+
let v = obj.getattr(key.str()?)?;
520+
values.push(v);
521+
}
522+
Ok(Self { keys, values })
523+
}
501524
}
502525

503526
impl<'de> MapAccess<'de> for MapDeserializer<'_> {

tests/check_revertible.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use maplit::hashmap;
2-
use pyo3::prelude::*;
2+
use pyo3::{ffi::c_str, prelude::*};
33
use serde::{Deserialize, Serialize};
44
use serde_pyobject::{from_pyobject, to_pyobject};
55

@@ -133,3 +133,50 @@ fn struct_variant() {
133133
b: 30,
134134
});
135135
}
136+
137+
#[test]
138+
fn check_python_object() {
139+
#[derive(Debug, PartialEq, Serialize, Deserialize)]
140+
struct MyClass {
141+
name: String,
142+
age: i32,
143+
}
144+
145+
Python::with_gil(|py| {
146+
// Create an instance of Python object
147+
py.run(
148+
c_str!(
149+
r#"
150+
class MyClass:
151+
def __init__(self, name: str, age: int):
152+
self.name = name
153+
self.age = age
154+
"#
155+
),
156+
None,
157+
None,
158+
)
159+
.unwrap();
160+
// Create an instance of MyClass
161+
let my_python_class = py
162+
.eval(
163+
c_str!(
164+
r#"
165+
MyClass("John", 30)
166+
"#
167+
),
168+
None,
169+
None,
170+
)
171+
.unwrap();
172+
173+
let my_rust_class = MyClass {
174+
name: "John".to_string(),
175+
age: 30,
176+
};
177+
let any: Bound<'_, PyAny> = to_pyobject(py, &my_rust_class).unwrap();
178+
let rust_version: MyClass = from_pyobject(my_python_class).unwrap();
179+
let python_version: MyClass = from_pyobject(any).unwrap();
180+
assert_eq!(rust_version, python_version);
181+
})
182+
}

0 commit comments

Comments
 (0)