2020-08-24 22:00:12 +00:00
use pyo3 ::exceptions ::PyValueError ;
use pyo3 ::prelude ::* ;
use pyo3 ::types ::{ PyDict , PyString , PyTuple } ;
2020-08-25 19:33:36 +00:00
use pyo3 ::PyMappingProtocol ;
2020-08-24 22:00:12 +00:00
#[ macro_use ]
mod common ;
#[ derive(Debug, FromPyObject) ]
pub struct A < ' a > {
2020-08-26 20:13:14 +00:00
#[ pyo3(attribute) ]
2020-08-24 22:00:12 +00:00
s : String ,
2020-08-26 20:13:14 +00:00
#[ pyo3(item) ]
2020-08-24 22:00:12 +00:00
t : & ' a PyString ,
2020-08-29 08:40:05 +00:00
#[ pyo3(attribute( " foo " )) ]
2020-08-24 22:00:12 +00:00
p : & ' a PyAny ,
}
#[ pyclass ]
pub struct PyA {
#[ pyo3(get) ]
s : String ,
#[ pyo3(get) ]
foo : Option < String > ,
}
#[ pyproto ]
impl PyMappingProtocol for PyA {
fn __getitem__ ( & self , key : String ) -> pyo3 ::PyResult < String > {
if key = = " t " {
Ok ( " bar " . into ( ) )
} else {
2020-08-25 19:33:36 +00:00
Err ( PyValueError ::new_err ( " Failed " ) )
2020-08-24 22:00:12 +00:00
}
}
}
#[ test ]
fn test_named_fields_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let pya = PyA {
s : " foo " . into ( ) ,
foo : None ,
} ;
let py_c = Py ::new ( py , pya ) . unwrap ( ) ;
let a : A = FromPyObject ::extract ( py_c . as_ref ( py ) ) . expect ( " Failed to extract A from PyA " ) ;
assert_eq! ( a . s , " foo " ) ;
assert_eq! ( a . t . to_string_lossy ( ) , " bar " ) ;
assert! ( a . p . is_none ( ) ) ;
}
#[ derive(Debug, FromPyObject) ]
2020-08-26 20:13:14 +00:00
#[ pyo3(transparent) ]
2020-08-24 22:00:12 +00:00
pub struct B {
test : String ,
}
#[ test ]
fn test_transparent_named_field_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let test = " test " . into_py ( py ) ;
let b : B = FromPyObject ::extract ( test . as_ref ( py ) ) . expect ( " Failed to extract B from String " ) ;
assert_eq! ( b . test , " test " ) ;
let test : PyObject = 1. into_py ( py ) ;
let b = B ::extract ( test . as_ref ( py ) ) ;
assert! ( b . is_err ( ) )
}
#[ derive(Debug, FromPyObject) ]
2020-08-26 20:13:14 +00:00
#[ pyo3(transparent) ]
2020-08-24 22:00:12 +00:00
pub struct D < T > {
test : T ,
}
#[ test ]
fn test_generic_transparent_named_field_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let test = " test " . into_py ( py ) ;
let d : D < String > =
D ::extract ( test . as_ref ( py ) ) . expect ( " Failed to extract D<String> from String " ) ;
assert_eq! ( d . test , " test " ) ;
let test = 1 usize . into_py ( py ) ;
let d : D < usize > = D ::extract ( test . as_ref ( py ) ) . expect ( " Failed to extract D<usize> from String " ) ;
assert_eq! ( d . test , 1 ) ;
}
#[ derive(Debug, FromPyObject) ]
pub struct E < T , T2 > {
test : T ,
test2 : T2 ,
}
#[ pyclass ]
2021-05-31 22:23:54 +00:00
#[ derive(Clone) ]
2020-08-24 22:00:12 +00:00
pub struct PyE {
#[ pyo3(get) ]
test : String ,
#[ pyo3(get) ]
test2 : usize ,
}
#[ test ]
fn test_generic_named_fields_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let pye = PyE {
test : " test " . into ( ) ,
test2 : 2 ,
}
. into_py ( py ) ;
let e : E < String , usize > =
E ::extract ( pye . as_ref ( py ) ) . expect ( " Failed to extract E<String, usize> from PyE " ) ;
assert_eq! ( e . test , " test " ) ;
assert_eq! ( e . test2 , 2 ) ;
let e = E ::< usize , usize > ::extract ( pye . as_ref ( py ) ) ;
assert! ( e . is_err ( ) ) ;
}
#[ derive(Debug, FromPyObject) ]
pub struct C {
2020-08-29 08:40:05 +00:00
#[ pyo3(attribute( " test " )) ]
2020-08-24 22:00:12 +00:00
test : String ,
}
#[ test ]
fn test_named_field_with_ext_fn ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let pyc = PyE {
test : " foo " . into ( ) ,
test2 : 0 ,
}
. into_py ( py ) ;
let c = C ::extract ( pyc . as_ref ( py ) ) . expect ( " Failed to extract C from PyE " ) ;
assert_eq! ( c . test , " foo " ) ;
}
2021-05-31 22:23:54 +00:00
#[ derive(Debug, FromPyObject) ]
2020-08-24 22:00:12 +00:00
pub struct Tuple ( String , usize ) ;
#[ test ]
fn test_tuple_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let tup = PyTuple ::new ( py , & [ 1. into_py ( py ) , " test " . into_py ( py ) ] ) ;
let tup = Tuple ::extract ( tup . as_ref ( ) ) ;
assert! ( tup . is_err ( ) ) ;
let tup = PyTuple ::new ( py , & [ " test " . into_py ( py ) , 1. into_py ( py ) ] ) ;
let tup = Tuple ::extract ( tup . as_ref ( ) ) . expect ( " Failed to extract Tuple from PyTuple " ) ;
assert_eq! ( tup . 0 , " test " ) ;
assert_eq! ( tup . 1 , 1 ) ;
}
#[ derive(FromPyObject) ]
pub struct TransparentTuple ( String ) ;
#[ test ]
fn test_transparent_tuple_struct ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
2020-08-26 20:13:14 +00:00
let tup : PyObject = 1. into_py ( py ) ;
let tup = TransparentTuple ::extract ( tup . as_ref ( py ) ) ;
2020-08-24 22:00:12 +00:00
assert! ( tup . is_err ( ) ) ;
2020-08-26 20:13:14 +00:00
let test = " test " . into_py ( py ) ;
let tup = TransparentTuple ::extract ( test . as_ref ( py ) )
2020-08-24 22:00:12 +00:00
. expect ( " Failed to extract TransparentTuple from PyTuple " ) ;
assert_eq! ( tup . 0 , " test " ) ;
}
2021-05-31 22:23:54 +00:00
#[ pyclass ]
struct PyBaz {
#[ pyo3(get) ]
tup : ( String , String ) ,
#[ pyo3(get) ]
e : PyE ,
}
#[ derive(Debug, FromPyObject) ]
struct Baz < U , T > {
e : E < U , T > ,
tup : Tuple ,
}
#[ test ]
fn test_struct_nested_type_errors ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let pybaz = PyBaz {
tup : ( " test " . into ( ) , " test " . into ( ) ) ,
e : PyE {
test : " foo " . into ( ) ,
test2 : 0 ,
} ,
}
. into_py ( py ) ;
2021-06-01 20:44:16 +00:00
let test : PyResult < Baz < String , usize > > = FromPyObject ::extract ( pybaz . as_ref ( py ) ) ;
assert! ( test . is_err ( ) ) ;
2021-05-31 22:23:54 +00:00
assert_eq! (
" TypeError: failed to extract field Baz.tup \n \n Caused by: \n TypeError: failed to extract field Tuple.1 \n \n Caused by: \n TypeError: 'str' object cannot be interpreted as an integer \n \n " ,
2021-06-01 20:44:16 +00:00
test . unwrap_err ( ) . to_string ( )
2021-05-31 22:23:54 +00:00
) ;
}
#[ test ]
fn test_struct_nested_type_errors_with_generics ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let pybaz = PyBaz {
tup : ( " test " . into ( ) , " test " . into ( ) ) ,
e : PyE {
test : " foo " . into ( ) ,
test2 : 0 ,
} ,
}
. into_py ( py ) ;
2021-06-01 20:44:16 +00:00
let test : PyResult < Baz < usize , String > > = FromPyObject ::extract ( pybaz . as_ref ( py ) ) ;
assert! ( test . is_err ( ) ) ;
2021-05-31 22:23:54 +00:00
assert_eq! (
" TypeError: failed to extract field Baz.e \n \n Caused by: \n TypeError: failed to extract field E.test \n \n Caused by: \n TypeError: \' str \' object cannot be interpreted as an integer \n \n " ,
2021-06-01 20:44:16 +00:00
test . unwrap_err ( ) . to_string ( )
) ;
}
#[ derive(Debug, FromPyObject) ]
2021-06-07 08:18:38 +00:00
#[ pyo3(transparent) ]
2021-06-01 20:44:16 +00:00
pub struct TransparentStruct {
a : String ,
}
#[ test ]
fn test_transparent_struct_error_message ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let tup : PyObject = 1. into_py ( py ) ;
let tup = TransparentStruct ::extract ( tup . as_ref ( py ) ) ;
assert! ( tup . is_err ( ) ) ;
assert_eq! (
2021-06-07 08:18:38 +00:00
" TypeError: failed to extract field TransparentStruct.a \n \n Caused by: \n TypeError: \' int \' object cannot be converted to \' PyString \' \n " ,
2021-06-01 20:44:16 +00:00
tup . unwrap_err ( ) . to_string ( )
) ;
}
2020-08-24 22:00:12 +00:00
#[ derive(Debug, FromPyObject) ]
pub enum Foo < ' a > {
TupleVar ( usize , String ) ,
StructVar {
test : & ' a PyString ,
} ,
2020-08-26 20:13:14 +00:00
#[ pyo3(transparent) ]
2020-08-24 22:00:12 +00:00
TransparentTuple ( usize ) ,
2020-08-26 20:13:14 +00:00
#[ pyo3(transparent) ]
2020-08-24 22:00:12 +00:00
TransparentStructVar {
a : Option < String > ,
} ,
StructVarGetAttrArg {
2020-08-29 08:40:05 +00:00
#[ pyo3(attribute( " bla " )) ]
2020-08-24 22:00:12 +00:00
a : bool ,
} ,
StructWithGetItem {
2020-08-26 20:13:14 +00:00
#[ pyo3(item) ]
2020-08-24 22:00:12 +00:00
a : String ,
} ,
StructWithGetItemArg {
2020-08-29 08:40:05 +00:00
#[ pyo3(item( " foo " )) ]
2020-08-24 22:00:12 +00:00
a : String ,
} ,
2020-08-26 20:13:14 +00:00
#[ pyo3(transparent) ]
2020-08-24 22:00:12 +00:00
CatchAll ( & ' a PyAny ) ,
}
#[ pyclass ]
pub struct PyBool {
#[ pyo3(get) ]
bla : bool ,
}
#[ test ]
fn test_enum ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let tup = PyTuple ::new ( py , & [ 1. into_py ( py ) , " test " . into_py ( py ) ] ) ;
let f = Foo ::extract ( tup . as_ref ( ) ) . expect ( " Failed to extract Foo from tuple " ) ;
match f {
Foo ::TupleVar ( test , test2 ) = > {
assert_eq! ( test , 1 ) ;
assert_eq! ( test2 , " test " ) ;
}
_ = > panic! ( " Expected extracting Foo::TupleVar, got {:?} " , f ) ,
}
let pye = PyE {
test : " foo " . into ( ) ,
test2 : 0 ,
}
. into_py ( py ) ;
let f = Foo ::extract ( pye . as_ref ( py ) ) . expect ( " Failed to extract Foo from PyE " ) ;
match f {
Foo ::StructVar { test } = > assert_eq! ( test . to_string_lossy ( ) , " foo " ) ,
_ = > panic! ( " Expected extracting Foo::StructVar, got {:?} " , f ) ,
}
let int : PyObject = 1. into_py ( py ) ;
let f = Foo ::extract ( int . as_ref ( py ) ) . expect ( " Failed to extract Foo from int " ) ;
match f {
Foo ::TransparentTuple ( test ) = > assert_eq! ( test , 1 ) ,
_ = > panic! ( " Expected extracting Foo::TransparentTuple, got {:?} " , f ) ,
}
let none = py . None ( ) ;
let f = Foo ::extract ( none . as_ref ( py ) ) . expect ( " Failed to extract Foo from int " ) ;
match f {
Foo ::TransparentStructVar { a } = > assert! ( a . is_none ( ) ) ,
_ = > panic! ( " Expected extracting Foo::TransparentStructVar, got {:?} " , f ) ,
}
let pybool = PyBool { bla : true } . into_py ( py ) ;
let f = Foo ::extract ( pybool . as_ref ( py ) ) . expect ( " Failed to extract Foo from PyBool " ) ;
match f {
Foo ::StructVarGetAttrArg { a } = > assert! ( a ) ,
_ = > panic! ( " Expected extracting Foo::StructVarGetAttrArg, got {:?} " , f ) ,
}
let dict = PyDict ::new ( py ) ;
dict . set_item ( " a " , " test " ) . expect ( " Failed to set item " ) ;
let f = Foo ::extract ( dict . as_ref ( ) ) . expect ( " Failed to extract Foo from dict " ) ;
match f {
Foo ::StructWithGetItem { a } = > assert_eq! ( a , " test " ) ,
_ = > panic! ( " Expected extracting Foo::StructWithGetItem, got {:?} " , f ) ,
}
let dict = PyDict ::new ( py ) ;
dict . set_item ( " foo " , " test " ) . expect ( " Failed to set item " ) ;
let f = Foo ::extract ( dict . as_ref ( ) ) . expect ( " Failed to extract Foo from dict " ) ;
match f {
Foo ::StructWithGetItemArg { a } = > assert_eq! ( a , " test " ) ,
_ = > panic! ( " Expected extracting Foo::StructWithGetItemArg, got {:?} " , f ) ,
}
let dict = PyDict ::new ( py ) ;
let f = Foo ::extract ( dict . as_ref ( ) ) . expect ( " Failed to extract Foo from dict " ) ;
match f {
Foo ::CatchAll ( any ) = > {
let d = < & PyDict > ::extract ( any ) . expect ( " Expected pydict " ) ;
assert! ( d . is_empty ( ) ) ;
}
_ = > panic! ( " Expected extracting Foo::CatchAll, got {:?} " , f ) ,
}
}
2020-08-25 19:33:36 +00:00
#[ derive(Debug, FromPyObject) ]
2020-08-24 22:00:12 +00:00
pub enum Bar {
2020-08-26 20:13:14 +00:00
#[ pyo3(annotation = " str " ) ]
2020-08-24 22:00:12 +00:00
A ( String ) ,
2020-08-26 20:13:14 +00:00
#[ pyo3(annotation = " uint " ) ]
2020-08-24 22:00:12 +00:00
B ( usize ) ,
2021-06-07 08:18:38 +00:00
#[ pyo3(annotation = " int " , transparent) ]
2020-08-24 22:00:12 +00:00
C ( isize ) ,
}
#[ test ]
fn test_err_rename ( ) {
let gil = Python ::acquire_gil ( ) ;
let py = gil . python ( ) ;
let dict = PyDict ::new ( py ) ;
let f = Bar ::extract ( dict . as_ref ( ) ) ;
assert! ( f . is_err ( ) ) ;
2020-08-25 19:33:36 +00:00
assert_eq! (
f . unwrap_err ( ) . to_string ( ) ,
2021-06-07 08:18:38 +00:00
" TypeError: Failed to extract type Bar \n \n Caused by: \n TypeError: \' dict \' object cannot be converted to \' Union[str, uint, int] \' \n \n TypeError: failed to extract inner field of Bar :: A \n \n Caused by: \n TypeError: \' dict \' object cannot be converted to \' PyString \' \n \n TypeError: failed to extract inner field of Bar :: B \n \n Caused by: \n TypeError: \' dict \' object cannot be interpreted as an integer \n \n TypeError: failed to extract inner field of Bar :: C \n \n Caused by: \n TypeError: \' dict \' object cannot be interpreted as an integer \n \n "
2020-08-25 19:33:36 +00:00
) ;
2020-08-24 22:00:12 +00:00
}
2021-02-20 15:15:20 +00:00
#[ derive(Debug, FromPyObject) ]
pub struct Zap {
#[ pyo3(item) ]
name : String ,
#[ pyo3(from_py_with = " PyAny::len " , item( " my_object " )) ]
some_object_length : usize ,
}
#[ test ]
fn test_from_py_with ( ) {
Python ::with_gil ( | py | {
let py_zap = py
. eval (
r # "{"name": "whatever", "my_object": [1, 2, 3]}"# ,
None ,
None ,
)
. expect ( " failed to create dict " ) ;
let zap = Zap ::extract ( py_zap ) . unwrap ( ) ;
assert_eq! ( zap . name , " whatever " ) ;
assert_eq! ( zap . some_object_length , 3 usize ) ;
} ) ;
}