File tree Expand file tree Collapse file tree 2 files changed +71
-1
lines changed
Expand file tree Collapse file tree 2 files changed +71
-1
lines changed Original file line number Diff line number Diff 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
503526impl < ' de > MapAccess < ' de > for MapDeserializer < ' _ > {
Original file line number Diff line number Diff line change 11use maplit:: hashmap;
2- use pyo3:: prelude:: * ;
2+ use pyo3:: { ffi :: c_str , prelude:: * } ;
33use serde:: { Deserialize , Serialize } ;
44use 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+ }
You can’t perform that action at this time.
0 commit comments