Merge pull request #343 from PyO3/into_py_tuple_no_more

Replace IntoPyTuple with IntoPy<Py<PyTuple>>
This commit is contained in:
konstin 2019-02-12 23:36:49 +01:00 committed by GitHub
commit 37088024f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 72 additions and 84 deletions

View file

@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Renamed `py_exception` to `create_exception` and refactored the error macros.
* Renamed `wrap_function!` to `wrap_pyfunction!`
* Migrated to the 2018 edition
* Replace `IntoPyTuple` with `IntoPy<Py<PyTuple>>`. Eventually `IntoPy<T>` should replace `ToPyObject` and be itself implemented through `FromPy<T>`
### Removed

View file

@ -10,22 +10,6 @@ The easiest way to convert a python object to a rust value is using `.extract()?
[`ToPyObject`] trait is a conversion trait that allows various objects to be converted into [`PyObject`][PyObject]. [`IntoPyObject`][IntoPyObject] serves the same purpose except it consumes `self`.
## `IntoPyTuple` trait
[`IntoPyTuple`][IntoPyTuple] trait is a conversion trait that allows various objects to be converted into [`PyTuple`][PyTuple] object.
For example, [`IntoPyTuple`][IntoPyTuple] trait is implemented for `()` so that you can convert it into a empty [`PyTuple`][PyTuple]
```rust
use pyo3::{Python, IntoPyTuple};
fn main() {
let gil = Python::acquire_gil();
let py = gil.python();
let py_tuple = ().into_tuple(py);
}
```
## `FromPyObject` and `RefFromPyObject` trait
## `*args` and `**kwargs` for python object call
@ -37,9 +21,7 @@ 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.
Both methods accept `args` and `kwargs` arguments. The `NoArgs` object represents an empty tuple object.
```rust
use pyo3::prelude::*;
@ -118,12 +100,15 @@ fn main() {
}
```
TODO
## `IntoPy<T>`
Many conversions in pyo3 can't use `std::convert::Into` because they need a gil token. That's why the `IntoPy<T>` trait offers an `into_py` methods that works just like `into` except for taking a `Python<'_>` as argument.
Eventually, traits such as `IntoPyObject` will be replaces by this trait and a `FromPy` trait will be added that will implement `IntoPy`, just like with `From` and `Into`.
[`ToPyObject`]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.ToPyObject.html
[IntoPyObject]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyObject.html
[PyObject]: https://docs.rs/pyo3/0.6.0-alpha.2/struct.PyObject.html
[IntoPyTuple]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyTuple.html
[PyTuple]: https://docs.rs/pyo3/0.6.0-alpha.2/struct.PyTuple.html
[ObjectProtocol]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.ObjectProtocol.html
[IntoPyDict]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyDict.html

View file

@ -4,11 +4,10 @@
use crate::err::{PyDowncastError, PyResult};
use crate::ffi;
use crate::instance::Py;
use crate::object::PyObject;
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::typeob::PyTypeInfo;
use crate::types::{PyObjectRef, PyTuple};
use crate::types::PyObjectRef;
/// Conversion trait that allows various objects to be converted into `PyObject`
pub trait ToPyObject {
@ -53,6 +52,12 @@ where
}
}
/// Similar to [std::convert::Into], just that it requires a gil token and there's
/// currently no corresponding [std::convert::From] part.
pub trait IntoPy<T>: Sized {
fn into_py(self, py: Python) -> T;
}
/// Conversion trait that allows various objects to be converted into `PyObject`
/// by consuming original object.
pub trait IntoPyObject {
@ -60,12 +65,6 @@ pub trait IntoPyObject {
fn into_object(self, py: Python) -> PyObject;
}
/// Conversion trait that allows various objects to be converted into `PyTuple` object.
pub trait IntoPyTuple {
/// Converts self into a PyTuple object.
fn into_tuple(self, py: Python) -> Py<PyTuple>;
}
/// `FromPyObject` is implemented by various types that can be extracted from
/// a Python object reference.
///

View file

@ -129,7 +129,7 @@
pub use crate::class::*;
pub use crate::conversion::{
FromPyObject, IntoPyObject, IntoPyTuple, PyTryFrom, PyTryInto, ReturnTypeIntoPyResult,
FromPyObject, IntoPy, IntoPyObject, PyTryFrom, PyTryInto, ReturnTypeIntoPyResult,
ToBorrowedObject, ToPyObject,
};
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};

View file

@ -1,6 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::conversion::{IntoPyObject, IntoPyTuple, ToPyObject};
use crate::conversion::{IntoPy, IntoPyObject, ToPyObject};
use crate::instance::Py;
use crate::object::PyObject;
use crate::python::Python;
@ -22,15 +22,15 @@ use crate::types::PyTuple;
pub struct NoArgs;
/// Converts `NoArgs` to an empty Python tuple.
impl IntoPyTuple for NoArgs {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
impl IntoPy<Py<PyTuple>> for NoArgs {
fn into_py(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
}
/// Converts `()` to an empty Python tuple.
impl IntoPyTuple for () {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
impl IntoPy<Py<PyTuple>> for () {
fn into_py(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py)
}
}

View file

@ -3,7 +3,7 @@
use std::ptr::NonNull;
use crate::conversion::{
FromPyObject, IntoPyObject, IntoPyTuple, PyTryFrom, ToBorrowedObject, ToPyObject,
FromPyObject, IntoPy, IntoPyObject, PyTryFrom, ToBorrowedObject, ToPyObject,
};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::ffi;
@ -11,6 +11,7 @@ use crate::instance::{AsPyRef, PyObjectWithGIL, PyRef, PyRefMut};
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::pythonrun;
use crate::types::{PyDict, PyObjectRef, PyTuple};
use crate::Py;
/// A python object
///
@ -181,11 +182,13 @@ impl PyObject {
/// Calls the object.
/// This is equivalent to the Python expression: 'self(*args, **kwargs)'
pub fn call<A>(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult<PyObject>
where
A: IntoPyTuple,
{
let args = args.into_tuple(py).into_ptr();
pub fn call(
&self,
py: Python,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
let args = args.into_py(py).into_ptr();
let kwargs = kwargs.into_ptr();
let result = unsafe {
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(self.as_ptr(), args, kwargs))
@ -205,10 +208,7 @@ impl PyObject {
/// Calls the object.
/// This is equivalent to the Python expression: 'self(*args)'
pub fn call1<A>(&self, py: Python, args: A) -> PyResult<PyObject>
where
A: IntoPyTuple,
{
pub fn call1(&self, py: Python, args: impl IntoPy<Py<PyTuple>>) -> PyResult<PyObject> {
self.call(py, args, None)
}
@ -218,11 +218,11 @@ impl PyObject {
&self,
py: Python,
name: &str,
args: impl IntoPyTuple,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
name.with_borrowed_ptr(py, |name| unsafe {
let args = args.into_tuple(py).into_ptr();
let args = args.into_py(py).into_ptr();
let kwargs = kwargs.into_ptr();
let ptr = ffi::PyObject_GetAttr(self.as_ptr(), name);
if ptr.is_null() {
@ -248,7 +248,7 @@ impl PyObject {
&self,
py: Python,
name: &str,
args: impl IntoPyTuple,
args: impl IntoPy<Py<PyTuple>>,
) -> PyResult<PyObject> {
self.call_method(py, name, args, None)
}

View file

@ -1,6 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::conversion::{FromPyObject, IntoPyTuple, PyTryFrom, ToBorrowedObject, ToPyObject};
use crate::conversion::{FromPyObject, IntoPy, PyTryFrom, ToBorrowedObject, ToPyObject};
use crate::err::{self, PyDowncastError, PyErr, PyResult};
use crate::exceptions::TypeError;
use crate::ffi;
@ -9,6 +9,7 @@ use crate::object::PyObject;
use crate::python::{IntoPyPointer, Python, ToPyPointer};
use crate::typeob::PyTypeInfo;
use crate::types::{PyDict, PyIterator, PyObjectRef, PyString, PyTuple, PyType};
use crate::Py;
use std::cmp::Ordering;
use std::os::raw::c_int;
@ -84,9 +85,11 @@ pub trait ObjectProtocol {
/// Calls the object.
/// This is equivalent to the Python expression: `self(*args, **kwargs)`
fn call<A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple;
fn call(
&self,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyObjectRef>;
/// Calls the object.
/// This is equivalent to the Python expression: `self()`
@ -94,9 +97,7 @@ pub trait ObjectProtocol {
/// Calls the object.
/// This is equivalent to the Python expression: `self(*args)`
fn call1<A>(&self, args: A) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple;
fn call1(&self, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyObjectRef>;
/// Calls a method on the object.
/// This is equivalent to the Python expression: `self.name(*args, **kwargs)`
@ -116,7 +117,7 @@ pub trait ObjectProtocol {
fn call_method(
&self,
name: &str,
args: impl IntoPyTuple,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyObjectRef>;
@ -126,7 +127,7 @@ pub trait ObjectProtocol {
/// Calls a method on the object with positional arguments only .
/// This is equivalent to the Python expression: `self.name(*args)`
fn call_method1(&self, name: &str, args: impl IntoPyTuple) -> PyResult<&PyObjectRef>;
fn call_method1(&self, name: &str, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyObjectRef>;
/// Retrieves the hash code of the object.
/// This is equivalent to the Python expression: `hash(self)`
@ -321,11 +322,12 @@ where
unsafe { ffi::PyCallable_Check(self.as_ptr()) != 0 }
}
fn call<A>(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple,
{
let args = args.into_tuple(self.py()).into_ptr();
fn call(
&self,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyObjectRef> {
let args = args.into_py(self.py()).into_ptr();
let kwargs = kwargs.into_ptr();
let result = unsafe {
let return_value = ffi::PyObject_Call(self.as_ptr(), args, kwargs);
@ -342,17 +344,14 @@ where
self.call(PyTuple::empty(self.py()), None)
}
fn call1<A>(&self, args: A) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple,
{
fn call1(&self, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyObjectRef> {
self.call(args, None)
}
fn call_method(
&self,
name: &str,
args: impl IntoPyTuple,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyObjectRef> {
name.with_borrowed_ptr(self.py(), |name| unsafe {
@ -361,7 +360,7 @@ where
if ptr.is_null() {
return Err(PyErr::fetch(py));
}
let args = args.into_tuple(py).into_ptr();
let args = args.into_py(py).into_ptr();
let kwargs = kwargs.into_ptr();
let result_ptr = ffi::PyObject_Call(ptr, args, kwargs);
let result = py.from_owned_ptr_or_err(result_ptr);
@ -376,7 +375,7 @@ where
self.call_method(name, PyTuple::empty(self.py()), None)
}
fn call_method1(&self, name: &str, args: impl IntoPyTuple) -> PyResult<&PyObjectRef> {
fn call_method1(&self, name: &str, args: impl IntoPy<Py<PyTuple>>) -> PyResult<&PyObjectRef> {
self.call_method(name, args, None)
}

View file

@ -2,7 +2,7 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use crate::conversion::{IntoPyTuple, ToPyObject};
use crate::conversion::{IntoPy, ToPyObject};
use crate::err::{PyErr, PyResult};
use crate::ffi;
use crate::instance::PyObjectWithGIL;
@ -10,7 +10,9 @@ use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol;
use crate::python::{Python, ToPyPointer};
use crate::typeob::PyTypeCreate;
use crate::types::PyTuple;
use crate::types::{exceptions, PyDict, PyObjectRef};
use crate::Py;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::str;
@ -104,10 +106,12 @@ impl PyModule {
/// Calls a function in the module.
/// This is equivalent to the Python expression: `getattr(module, name)(*args, **kwargs)`
pub fn call<A>(&self, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple,
{
pub fn call(
&self,
name: &str,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<&PyObjectRef> {
self.getattr(name)?.call(args, kwargs)
}
@ -121,7 +125,7 @@ impl PyModule {
/// This is equivalent to the Python expression: `getattr(module, name)(*args)`
pub fn call1<A>(&self, name: &str, args: A) -> PyResult<&PyObjectRef>
where
A: IntoPyTuple,
A: IntoPy<Py<PyTuple>>,
{
self.getattr(name)?.call1(args)
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use super::exceptions;
use crate::conversion::{FromPyObject, IntoPyObject, IntoPyTuple, PyTryFrom, ToPyObject};
use crate::conversion::{FromPyObject, IntoPy, IntoPyObject, PyTryFrom, ToPyObject};
use crate::err::{PyErr, PyResult};
use crate::ffi::{self, Py_ssize_t};
use crate::instance::{AsPyRef, Py, PyObjectWithGIL};
@ -131,20 +131,20 @@ impl<'a> IntoIterator for &'a PyTuple {
}
}
impl<'a> IntoPyTuple for &'a PyTuple {
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
impl<'a> IntoPy<Py<PyTuple>> for &'a PyTuple {
fn into_py(self, _py: Python) -> Py<PyTuple> {
unsafe { Py::from_borrowed_ptr(self.as_ptr()) }
}
}
impl IntoPyTuple for Py<PyTuple> {
fn into_tuple(self, _py: Python) -> Py<PyTuple> {
impl IntoPy<Py<PyTuple>> for Py<PyTuple> {
fn into_py(self, _py: Python) -> Py<PyTuple> {
self
}
}
impl<'a> IntoPyTuple for &'a str {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
impl<'a> IntoPy<Py<PyTuple>> for &'a str {
fn into_py(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New(1);
ffi::PyTuple_SetItem(ptr, 0, self.into_object(py).into_ptr());
@ -182,8 +182,8 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
}
}
impl <$($T: IntoPyObject),+> IntoPyTuple for ($($T,)+) {
fn into_tuple(self, py: Python) -> Py<PyTuple> {
impl <$($T: IntoPyObject),+> IntoPy<Py<PyTuple>> for ($($T,)+) {
fn into_py(self, py: Python) -> Py<PyTuple> {
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr());)+;