add IntoPyDictPointer impl for tuple
This commit is contained in:
parent
cd6558a19b
commit
06a0b0514b
|
@ -26,6 +26,76 @@ fn main() {
|
||||||
|
|
||||||
## `FromPyObject` and `RefFromPyObject` trait
|
## `FromPyObject` and `RefFromPyObject` trait
|
||||||
|
|
||||||
|
## `*args` and `**kwargs` for python object call
|
||||||
|
|
||||||
|
There are several way how to pass positional and keyword arguments to python object call.
|
||||||
|
[`ObjectProtocol`][ObjectProtocol] trait
|
||||||
|
provides two methods:
|
||||||
|
|
||||||
|
* `call` - call callable python object.
|
||||||
|
* `call_method` - call specific method on the object.
|
||||||
|
|
||||||
|
Both methods accept `args` and `kwargs` arguments. `args` argument is generate over
|
||||||
|
[`IntoPyTuple`][IntoPyTuple] trait. So args could be `PyTuple` instance or
|
||||||
|
rust tuple with up to 10 elements. Or `NoArgs` object which represents empty tuple object.
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
extern crate pyo3;
|
||||||
|
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let obj = SomeObject::new();
|
||||||
|
|
||||||
|
// call object without empty arguments
|
||||||
|
obj.call(NoArgs, NoArg);
|
||||||
|
|
||||||
|
// call object with PyTuple
|
||||||
|
let args = PyTuple::new(py, &[arg1, arg2, arg3]);
|
||||||
|
obj.call(args, NoArg);
|
||||||
|
|
||||||
|
// pass arguments as rust tuple
|
||||||
|
let args = (arg1, arg2, arg3);
|
||||||
|
obj.call(args, NoArg);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`kwargs` argument is generate over
|
||||||
|
[`IntoPyDictPointer`][IntoPyDictPointer] trait. `HashMap` or `BTreeMap` could be used as
|
||||||
|
keyword arguments. rust tuple with up to 10 elements where each element is tuple with size 2
|
||||||
|
could be used as kwargs as well. Or `NoArgs` object can be used to indicate that
|
||||||
|
no keywords areguments are provided.
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
extern crate pyo3;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let obj = SomeObject::new();
|
||||||
|
|
||||||
|
// call object with PyDict
|
||||||
|
let kwargs = PyDict::new(py);
|
||||||
|
kwargs.set_item(key, value);
|
||||||
|
obj.call(NoArg, kwargs);
|
||||||
|
|
||||||
|
// pass arguments as rust tuple
|
||||||
|
let kwargs = ((key1, val1), (key2, val2), (key3, val3));
|
||||||
|
obj.call(args, kwargs);
|
||||||
|
|
||||||
|
// pass arguments as HashMap
|
||||||
|
let mut kwargs = HashMap::<i32, i32>::new();
|
||||||
|
kwargs.insert(1, 1);
|
||||||
|
obj.call(args, kwargs);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
[ToPyObject]: https://pyo3.github.io/PyO3/pyo3/trait.ToPyObject.html
|
[ToPyObject]: https://pyo3.github.io/PyO3/pyo3/trait.ToPyObject.html
|
||||||
|
@ -33,3 +103,5 @@ TODO
|
||||||
[PyObject]: https://pyo3.github.io/PyO3/pyo3/struct.PyObject.html
|
[PyObject]: https://pyo3.github.io/PyO3/pyo3/struct.PyObject.html
|
||||||
[IntoPyTuple]: https://pyo3.github.io/PyO3/pyo3/trait.IntoPyTuple.html
|
[IntoPyTuple]: https://pyo3.github.io/PyO3/pyo3/trait.IntoPyTuple.html
|
||||||
[PyTuple]: https://pyo3.github.io/PyO3/pyo3/struct.PyTuple.html
|
[PyTuple]: https://pyo3.github.io/PyO3/pyo3/struct.PyTuple.html
|
||||||
|
[ObjectProtocol]: https://pyo3.github.io/PyO3/pyo3/trait.ObjectProtocol.html
|
||||||
|
[IntoPyDictPointer]: https://pyo3.github.io/PyO3/pyo3/trait.IntoPyDictPointer.html
|
||||||
|
|
|
@ -623,7 +623,7 @@ mod test {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let array = py.import("array").unwrap().call_method(
|
let array = py.import("array").unwrap().call_method(
|
||||||
"array", ("f", (1.0, 1.5, 2.0, 2.5)), NoArgs).unwrap();
|
"array", ("f", (1.0, 1.5, 2.0, 2.5)), ::NoArgs).unwrap();
|
||||||
let buffer = PyBuffer::get(py, array.into()).unwrap();
|
let buffer = PyBuffer::get(py, array.into()).unwrap();
|
||||||
assert_eq!(buffer.dimensions(), 1);
|
assert_eq!(buffer.dimensions(), 1);
|
||||||
assert_eq!(buffer.item_count(), 4);
|
assert_eq!(buffer.item_count(), 4);
|
||||||
|
|
|
@ -83,8 +83,15 @@ pub trait ObjectProtocol {
|
||||||
|
|
||||||
/// Calls a method on the object.
|
/// Calls a method on the object.
|
||||||
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
|
/// This is equivalent to the Python expression: 'self.name(*args, **kwargs)'
|
||||||
fn call_method<A, K>(&self, name: &str, args: A, kwargs: K)
|
///
|
||||||
-> PyResult<&PyObjectRef>
|
/// # Example
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let obj = SomePyObject::new();
|
||||||
|
/// let args = (arg1, arg2, arg3);
|
||||||
|
/// let kwargs = ((key1, value1), (key2, value2));
|
||||||
|
/// let pid = obj.call_mwthod("do_something", args, kwargs);
|
||||||
|
/// ```
|
||||||
|
fn call_method<A, K>(&self, name: &str, args: A, kwargs: K) -> PyResult<&PyObjectRef>
|
||||||
where A: IntoPyTuple,
|
where A: IntoPyTuple,
|
||||||
K: IntoPyDictPointer;
|
K: IntoPyDictPointer;
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,43 @@ impl <K, V> IntoPyDictPointer for collections::BTreeMap<K, V>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<K: ToPyObject, V: ToPyObject> IntoPyDictPointer for (K, V) {
|
||||||
|
default fn into_dict_ptr(self, py: Python) -> *mut ffi::PyObject {
|
||||||
|
let dict = PyDict::new(py);
|
||||||
|
dict.set_item(self.0, self.1).expect("Failed to set_item on dict");
|
||||||
|
dict.into_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dict_conversion ({$length:expr,$(($refN:ident, $n:tt, $T1:ident, $T2:ident)),+} => {
|
||||||
|
impl<$($T1: ToPyObject, $T2: ToPyObject),+> IntoPyDictPointer for ($(($T1,$T2),)+) {
|
||||||
|
fn into_dict_ptr(self, py: Python) -> *mut ffi::PyObject {
|
||||||
|
let dict = PyDict::new(py);
|
||||||
|
$(dict.set_item(self.$n.0, self.$n.1).expect("Failed to set_item on dict");)+;
|
||||||
|
dict.into_ptr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dict_conversion!(1, (ref0, 0, A1, A2));
|
||||||
|
dict_conversion!(2, (ref0, 0, A1, A2), (ref1, 1, B1, B2));
|
||||||
|
dict_conversion!(3, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2));
|
||||||
|
dict_conversion!(4, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2));
|
||||||
|
dict_conversion!(5, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2), (ref4, 4, E1, E2));
|
||||||
|
dict_conversion!(6, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2), (ref4, 4, E1, E2), (ref5, 5, F1, F2));
|
||||||
|
dict_conversion!(7, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2), (ref4, 4, E1, E2), (ref5, 5, F1, F2), (ref6, 6, G1, G2));
|
||||||
|
dict_conversion!(8, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2), (ref4, 4, E1, E2), (ref5, 5, F1, F2), (ref6, 6, G1, G2),
|
||||||
|
(ref7, 7, H1, H2));
|
||||||
|
dict_conversion!(9, (ref0, 0, A1, A2), (ref1, 1, B1, B2), (ref2, 2, C1, C2),
|
||||||
|
(ref3, 3, D1, D2), (ref4, 4, E1, E2), (ref5, 5, F1, F2), (ref6, 6, G1, G2),
|
||||||
|
(ref7, 7, H1, H2), (ref8, 8, I1, I2));
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
@ -502,7 +539,7 @@ mod test {
|
||||||
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -517,7 +554,7 @@ mod test {
|
||||||
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -532,7 +569,7 @@ mod test {
|
||||||
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -548,7 +585,7 @@ mod test {
|
||||||
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -563,7 +600,7 @@ mod test {
|
||||||
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(m.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -578,7 +615,41 @@ mod test {
|
||||||
let ob = unsafe{PyObject::from_owned_ptr(py, m)};
|
let ob = unsafe{PyObject::from_owned_ptr(py, m)};
|
||||||
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
||||||
|
|
||||||
|
assert!(py_map.len() == 1);
|
||||||
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tuple_into_dict() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let m = ((1, 1),).into_dict_ptr(py);
|
||||||
|
let ob = unsafe{PyObject::from_owned_ptr(py, m)};
|
||||||
|
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
||||||
|
|
||||||
assert!(py_map.len() == 1);
|
assert!(py_map.len() == 1);
|
||||||
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
assert!( py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
|
|
||||||
|
let m = ((1, 1), (2, 3)).into_dict_ptr(py);
|
||||||
|
let ob = unsafe{PyObject::from_owned_ptr(py, m)};
|
||||||
|
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
||||||
|
|
||||||
|
assert!(py_map.len() == 2);
|
||||||
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
|
assert!(py_map.get_item(2).unwrap().extract::<i32>().unwrap() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_simple_tuple_into_dict() {
|
||||||
|
let gil = Python::acquire_gil();
|
||||||
|
let py = gil.python();
|
||||||
|
|
||||||
|
let m = (1, 1).into_dict_ptr(py);
|
||||||
|
let ob = unsafe{PyObject::from_owned_ptr(py, m)};
|
||||||
|
let py_map = PyDict::try_from(ob.as_ref(py)).unwrap();
|
||||||
|
|
||||||
|
assert!(py_map.len() == 1);
|
||||||
|
assert!(py_map.get_item(1).unwrap().extract::<i32>().unwrap() == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue