diff --git a/CHANGELOG.md b/CHANGELOG.md index b2333925..88577dcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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>`. Eventually `IntoPy` should replace `ToPyObject` and be itself implemented through `FromPy` ### Removed diff --git a/guide/src/conversions.md b/guide/src/conversions.md index bb34661f..f3df8205 100644 --- a/guide/src/conversions.md +++ b/guide/src/conversions.md @@ -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` + +Many conversions in pyo3 can't use `std::convert::Into` because they need a gil token. That's why the `IntoPy` 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 diff --git a/src/conversion.rs b/src/conversion.rs index 50b5a698..f536df71 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -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: 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; -} - /// `FromPyObject` is implemented by various types that can be extracted from /// a Python object reference. /// diff --git a/src/lib.rs b/src/lib.rs index 01307fdd..949f7b24 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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}; diff --git a/src/noargs.rs b/src/noargs.rs index 135048bf..73b4e6aa 100644 --- a/src/noargs.rs +++ b/src/noargs.rs @@ -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 { +impl IntoPy> for NoArgs { + fn into_py(self, py: Python) -> Py { PyTuple::empty(py) } } /// Converts `()` to an empty Python tuple. -impl IntoPyTuple for () { - fn into_tuple(self, py: Python) -> Py { +impl IntoPy> for () { + fn into_py(self, py: Python) -> Py { PyTuple::empty(py) } } diff --git a/src/object.rs b/src/object.rs index 838891c0..981efeb5 100644 --- a/src/object.rs +++ b/src/object.rs @@ -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(&self, py: Python, args: A, kwargs: Option<&PyDict>) -> PyResult - where - A: IntoPyTuple, - { - let args = args.into_tuple(py).into_ptr(); + pub fn call( + &self, + py: Python, + args: impl IntoPy>, + kwargs: Option<&PyDict>, + ) -> PyResult { + 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(&self, py: Python, args: A) -> PyResult - where - A: IntoPyTuple, - { + pub fn call1(&self, py: Python, args: impl IntoPy>) -> PyResult { self.call(py, args, None) } @@ -218,11 +218,11 @@ impl PyObject { &self, py: Python, name: &str, - args: impl IntoPyTuple, + args: impl IntoPy>, kwargs: Option<&PyDict>, ) -> PyResult { 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>, ) -> PyResult { self.call_method(py, name, args, None) } diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index e3c20052..a8241414 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -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(&self, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyObjectRef> - where - A: IntoPyTuple; + fn call( + &self, + args: impl IntoPy>, + 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(&self, args: A) -> PyResult<&PyObjectRef> - where - A: IntoPyTuple; + fn call1(&self, args: impl IntoPy>) -> 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>, 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>) -> 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(&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>, + 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(&self, args: A) -> PyResult<&PyObjectRef> - where - A: IntoPyTuple, - { + fn call1(&self, args: impl IntoPy>) -> PyResult<&PyObjectRef> { self.call(args, None) } fn call_method( &self, name: &str, - args: impl IntoPyTuple, + args: impl IntoPy>, 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>) -> PyResult<&PyObjectRef> { self.call_method(name, args, None) } diff --git a/src/types/module.rs b/src/types/module.rs index 3f98977b..74eeee24 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -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(&self, name: &str, args: A, kwargs: Option<&PyDict>) -> PyResult<&PyObjectRef> - where - A: IntoPyTuple, - { + pub fn call( + &self, + name: &str, + args: impl IntoPy>, + 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(&self, name: &str, args: A) -> PyResult<&PyObjectRef> where - A: IntoPyTuple, + A: IntoPy>, { self.getattr(name)?.call1(args) } diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 6a3e7c04..0934f888 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -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 { +impl<'a> IntoPy> for &'a PyTuple { + fn into_py(self, _py: Python) -> Py { unsafe { Py::from_borrowed_ptr(self.as_ptr()) } } } -impl IntoPyTuple for Py { - fn into_tuple(self, _py: Python) -> Py { +impl IntoPy> for Py { + fn into_py(self, _py: Python) -> Py { self } } -impl<'a> IntoPyTuple for &'a str { - fn into_tuple(self, py: Python) -> Py { +impl<'a> IntoPy> for &'a str { + fn into_py(self, py: Python) -> Py { 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 { + impl <$($T: IntoPyObject),+> IntoPy> for ($($T,)+) { + fn into_py(self, py: Python) -> Py { unsafe { let ptr = ffi::PyTuple_New($length); $(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_object(py).into_ptr());)+;