Replace PyObject with type alias for Py<T>

This commit is contained in:
David Hewitt 2020-07-22 00:40:31 +01:00
parent 7901890974
commit f29e6bae7a
19 changed files with 232 additions and 411 deletions

View File

@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Rename `PYTHON_SYS_EXECUTABLE` to `PYO3_PYTHON`. The old name will continue to work but will be undocumented, and will be removed in a future release. [#1039](https://github.com/PyO3/pyo3/pull/1039) - Rename `PYTHON_SYS_EXECUTABLE` to `PYO3_PYTHON`. The old name will continue to work but will be undocumented, and will be removed in a future release. [#1039](https://github.com/PyO3/pyo3/pull/1039)
- `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047) - `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047)
- Change `PyIterator::from_object` to return `PyResult<PyIterator>` instead of `Result<PyIterator, PyDowncastError>`. [#1051](https://github.com/PyO3/pyo3/pull/1051) - Change `PyIterator::from_object` to return `PyResult<PyIterator>` instead of `Result<PyIterator, PyDowncastError>`. [#1051](https://github.com/PyO3/pyo3/pull/1051)
- `IntoPy` is no longer implied by `FromPy`. [#1063](https://github.com/PyO3/pyo3/pull/1063)
- `PyObject` is now just a type alias for `Py<PyAny>`. [#1063](https://github.com/PyO3/pyo3/pull/1063)
- Implement `Send + Sync` for `PyErr`. `PyErr::new`, `PyErr::from_type`, `PyException::py_err` and `PyException::into` have had these bounds added to their arguments. [#1067](https://github.com/PyO3/pyo3/pull/1067) - Implement `Send + Sync` for `PyErr`. `PyErr::new`, `PyErr::from_type`, `PyException::py_err` and `PyException::into` have had these bounds added to their arguments. [#1067](https://github.com/PyO3/pyo3/pull/1067)
- Change `#[pyproto]` to return NotImplemented for operators for which Python can try a reversed operation. [1072](https://github.com/PyO3/pyo3/pull/1072) - Change `#[pyproto]` to return NotImplemented for operators for which Python can try a reversed operation. [1072](https://github.com/PyO3/pyo3/pull/1072)
@ -28,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Remove `PyString::as_bytes`. [#1023](https://github.com/PyO3/pyo3/pull/1023) - Remove `PyString::as_bytes`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
- Remove `Python::register_any`. [#1023](https://github.com/PyO3/pyo3/pull/1023) - Remove `Python::register_any`. [#1023](https://github.com/PyO3/pyo3/pull/1023)
- Remove `GILGuard::acquire` from the public API. Use `Python::acquire_gil` or `Python::with_gil`. [#1036](https://github.com/PyO3/pyo3/pull/1036) - Remove `GILGuard::acquire` from the public API. Use `Python::acquire_gil` or `Python::with_gil`. [#1036](https://github.com/PyO3/pyo3/pull/1036)
- Remove `FromPy`. [#1063](https://github.com/PyO3/pyo3/pull/1063)
### Fixed ### Fixed
- Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027) - Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027)

View File

@ -2,7 +2,7 @@
//! Conversions between various states of Rust and Python types and their wrappers. //! Conversions between various states of Rust and Python types and their wrappers.
use crate::err::{self, PyDowncastError, PyResult}; use crate::err::{self, PyDowncastError, PyResult};
use crate::object::PyObject; use crate::instance::PyObject;
use crate::type_object::PyTypeInfo; use crate::type_object::PyTypeInfo;
use crate::types::PyTuple; use crate::types::PyTuple;
use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python};
@ -383,7 +383,7 @@ where
/// Converts `()` to an empty Python tuple. /// Converts `()` to an empty Python tuple.
impl IntoPy<Py<PyTuple>> for () { impl IntoPy<Py<PyTuple>> for () {
fn into_py(self, py: Python) -> Py<PyTuple> { fn into_py(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py).into_py(py) PyTuple::empty(py).into()
} }
} }

View File

@ -6,8 +6,8 @@ use crate::type_object::PyTypeObject;
use crate::types::PyType; use crate::types::PyType;
use crate::{exceptions, ffi}; use crate::{exceptions, ffi};
use crate::{ use crate::{
AsPyPointer, FromPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyNativeType, PyObject, AsPyPointer, FromPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyNativeType, PyObject, Python,
Python, ToBorrowedObject, ToPyObject, ToBorrowedObject, ToPyObject,
}; };
use libc::c_int; use libc::c_int;
use std::borrow::Cow; use std::borrow::Cow;

View File

@ -1,9 +1,10 @@
// Copyright (c) 2017-present PyO3 Project and Contributors // Copyright (c) 2017-present PyO3 Project and Contributors
use crate::err::{PyErr, PyResult}; use crate::conversion::{PyTryFrom, ToBorrowedObject};
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::gil; use crate::gil;
use crate::object::PyObject;
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell}; use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::type_object::PyBorrowFlagLayout; use crate::type_object::PyBorrowFlagLayout;
use crate::types::{PyDict, PyTuple};
use crate::{ use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer, ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
@ -114,6 +115,11 @@ where
} }
impl<T> Py<T> { impl<T> Py<T> {
/// For internal conversions
pub(crate) unsafe fn from_not_null(ptr: NonNull<ffi::PyObject>) -> Self {
Self(ptr, PhantomData)
}
/// Creates a `Py<T>` instance for the given FFI pointer. /// Creates a `Py<T>` instance for the given FFI pointer.
/// ///
/// This moves ownership over the pointer into the `Py<T>`. /// This moves ownership over the pointer into the `Py<T>`.
@ -187,6 +193,168 @@ impl<T> Py<T> {
mem::forget(self); mem::forget(self);
pointer pointer
} }
/// Constructs a `PyObject` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `None` if the pointer is NULL.
pub unsafe fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option<Self> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Some(Py(nonnull_ptr, PhantomData)),
None => None,
}
}
/// Creates a `PyObject` instance for the given Python FFI pointer.
/// Calls `Py_INCREF()` on the ptr.
/// Returns `Err(PyErr)` if the pointer is NULL.
pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Self> {
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(Self::from_borrowed_ptr(py, ptr))
}
}
/// Creates a `PyObject` instance for the given Python FFI pointer.
/// Calls `Py_INCREF()` on the ptr.
/// Returns `None` if the pointer is NULL.
pub unsafe fn from_borrowed_ptr_or_opt(py: Python, ptr: *mut ffi::PyObject) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Self::from_borrowed_ptr(py, ptr))
}
}
/// Returns whether the object is considered to be None.
///
/// This is equivalent to the Python expression `self is None`.
pub fn is_none(&self, _py: Python) -> bool {
unsafe { ffi::Py_None() == self.as_ptr() }
}
/// Returns whether the object is considered to be true.
///
/// This is equivalent to the Python expression `bool(self)`.
pub fn is_true(&self, py: Python) -> PyResult<bool> {
let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
} else {
Ok(v != 0)
}
}
/// Casts the PyObject to a concrete Python object type.
///
/// This can cast only to native Python types, not types implemented in Rust.
pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError>
where
D: PyTryFrom<'p>,
{
D::try_from(unsafe { py.from_borrowed_ptr::<PyAny>(self.as_ptr()) })
}
/// Extracts some type from the Python object.
///
/// This is a wrapper function around `FromPyObject::extract()`.
pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult<D>
where
D: FromPyObject<'p>,
{
FromPyObject::extract(unsafe { py.from_borrowed_ptr(self.as_ptr()) })
}
/// Retrieves an attribute value.
///
/// This is equivalent to the Python expression `self.attr_name`.
pub fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject>
where
N: ToPyObject,
{
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
})
}
/// Calls the object.
///
/// This is equivalent to the Python expression `self(*args, **kwargs)`.
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))
};
unsafe {
ffi::Py_XDECREF(args);
ffi::Py_XDECREF(kwargs);
}
result
}
/// Calls the object with only positional arguments.
///
/// This is equivalent to the Python expression `self(*args)`.
pub fn call1(&self, py: Python, args: impl IntoPy<Py<PyTuple>>) -> PyResult<PyObject> {
self.call(py, args, None)
}
/// Calls the object without arguments.
///
/// This is equivalent to the Python expression `self()`.
pub fn call0(&self, py: Python) -> PyResult<PyObject> {
self.call(py, (), None)
}
/// Calls a method on the object.
///
/// This is equivalent to the Python expression `self.name(*args, **kwargs)`.
pub fn call_method(
&self,
py: Python,
name: &str,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
name.with_borrowed_ptr(py, |name| unsafe {
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() {
return Err(PyErr::fetch(py));
}
let result = PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(ptr, args, kwargs));
ffi::Py_DECREF(ptr);
ffi::Py_XDECREF(args);
ffi::Py_XDECREF(kwargs);
result
})
}
/// Calls a method on the object with only positional arguments.
///
/// This is equivalent to the Python expression `self.name(*args)`.
pub fn call_method1(
&self,
py: Python,
name: &str,
args: impl IntoPy<Py<PyTuple>>,
) -> PyResult<PyObject> {
self.call_method(py, name, args, None)
}
/// Calls a method on the object with no arguments.
///
/// This is equivalent to the Python expression `self.name()`.
pub fn call_method0(&self, py: Python, name: &str) -> PyResult<PyObject> {
self.call_method(py, name, (), None)
}
} }
/// Retrieves `&'py` types from `Py<T>` or `PyObject`. /// Retrieves `&'py` types from `Py<T>` or `PyObject`.
@ -274,16 +442,25 @@ impl<T> IntoPyPointer for Py<T> {
} }
} }
// Native types `&T` can be converted to `Py<T>` impl<T> std::convert::From<&'_ T> for PyObject
impl<'a, T> std::convert::From<&'a T> for Py<T>
where where
T: AsPyPointer + PyNativeType, T: AsPyPointer + PyNativeType,
{ {
fn from(obj: &'a T) -> Self { fn from(obj: &T) -> Self {
unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) } unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) }
} }
} }
impl<T> std::convert::From<Py<T>> for PyObject
where
T: AsRef<PyAny>,
{
fn from(other: Py<T>) -> Self {
let Py(ptr, _) = other;
Py(ptr, PhantomData)
}
}
// `&PyCell<T>` can be converted to `Py<T>` // `&PyCell<T>` can be converted to `Py<T>`
impl<'a, T> std::convert::From<&PyCell<T>> for Py<T> impl<'a, T> std::convert::From<&PyCell<T>> for Py<T>
where where
@ -337,31 +514,6 @@ impl<T> Drop for Py<T> {
} }
} }
impl<T> std::convert::From<Py<T>> for PyObject {
#[inline]
fn from(ob: Py<T>) -> Self {
unsafe { PyObject::from_not_null(ob.into_non_null()) }
}
}
impl<'a, T> std::convert::From<&'a T> for PyObject
where
T: AsPyPointer + PyNativeType,
{
fn from(ob: &'a T) -> Self {
unsafe { Py::<T>::from_borrowed_ptr(ob.py(), ob.as_ptr()) }.into()
}
}
impl<'a, T> std::convert::From<&'a mut T> for PyObject
where
T: AsPyPointer + PyNativeType,
{
fn from(ob: &'a mut T) -> Self {
unsafe { Py::<T>::from_borrowed_ptr(ob.py(), ob.as_ptr()) }.into()
}
}
impl<'a, T> FromPyObject<'a> for Py<T> impl<'a, T> FromPyObject<'a> for Py<T>
where where
T: PyTypeInfo, T: PyTypeInfo,
@ -406,16 +558,30 @@ impl<T> std::fmt::Debug for Py<T> {
} }
} }
pub type PyObject = Py<PyAny>;
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Py; use super::{Py, PyObject};
use crate::ffi;
use crate::types::PyDict; use crate::types::PyDict;
use crate::{AsPyPointer, Python}; use crate::{ffi, AsPyPointer, Python};
#[test]
fn test_call_for_non_existing_method() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj: PyObject = PyDict::new(py).into();
assert!(obj.call_method0(py, "asdf").is_err());
assert!(obj
.call_method(py, "nonexistent_method", (1,), None)
.is_err());
assert!(obj.call_method0(py, "nonexistent_method").is_err());
assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err());
}
#[test] #[test]
fn py_from_dict() { fn py_from_dict() {
let dict = { let dict: Py<PyDict> = {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let native = PyDict::new(py); let native = PyDict::new(py);

View File

@ -140,8 +140,7 @@ pub use crate::conversion::{
}; };
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult}; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};
pub use crate::gil::{GILGuard, GILPool}; pub use crate::gil::{GILGuard, GILPool};
pub use crate::instance::{AsPyRef, Py, PyNativeType}; pub use crate::instance::{AsPyRef, Py, PyNativeType, PyObject};
pub use crate::object::PyObject;
pub use crate::pycell::{PyCell, PyRef, PyRefMut}; pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass::PyClass; pub use crate::pyclass::PyClass;
pub use crate::pyclass_init::PyClassInitializer; pub use crate::pyclass_init::PyClassInitializer;
@ -184,7 +183,6 @@ mod instance;
#[macro_use] #[macro_use]
mod internal_tricks; mod internal_tricks;
pub mod marshal; pub mod marshal;
mod object;
pub mod once_cell; pub mod once_cell;
pub mod panic; pub mod panic;
pub mod prelude; pub mod prelude;

View File

@ -1,353 +0,0 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::err::{PyDowncastError, PyErr, PyResult};
use crate::ffi;
use crate::gil;
use crate::instance::{AsPyRef, PyNativeType};
use crate::types::{PyAny, PyDict, PyTuple};
use crate::{AsPyPointer, Py, Python};
use crate::{FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, ToBorrowedObject, ToPyObject};
use std::ptr::NonNull;
/// A Python object of any type.
///
/// The Python object's lifetime is managed by Python's garbage collector,
/// so to access the object API, a `Python<'py>` GIL token is required.
///
/// See [the guide](https://pyo3.rs/master/types.html) for an explanation
/// of the different Python object types.
///
/// Technically, it is a safe wrapper around `NonNull<ffi::PyObject>`.
#[derive(Debug)]
#[repr(transparent)]
pub struct PyObject(NonNull<ffi::PyObject>);
// `PyObject` is thread-safe, any Python related operations require a Python<'p> token.
unsafe impl Send for PyObject {}
unsafe impl Sync for PyObject {}
impl PyObject {
/// For internal conversions
pub(crate) unsafe fn from_not_null(ptr: NonNull<ffi::PyObject>) -> PyObject {
PyObject(ptr)
}
/// Creates a `PyObject` instance for the given FFI pointer.
/// This moves ownership over the pointer into the `PyObject`.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
);
PyObject(NonNull::new_unchecked(ptr))
}
/// Creates a `PyObject` instance for the given FFI pointer.
/// Panics if the pointer is NULL.
/// Undefined behavior if the pointer is invalid.
#[inline]
pub unsafe fn from_owned_ptr_or_panic(py: Python, ptr: *mut ffi::PyObject) -> PyObject {
match NonNull::new(ptr) {
Some(nonnull_ptr) => PyObject(nonnull_ptr),
None => {
crate::err::panic_after_error(py);
}
}
}
/// Constructs a `PyObject` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is NULL.
pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<PyObject> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Ok(PyObject(nonnull_ptr)),
None => Err(PyErr::fetch(py)),
}
}
/// Constructs a `PyObject` from the result of a Python FFI call that
/// returns a new reference (owned pointer).
/// Returns `None` if the pointer is NULL.
pub unsafe fn from_owned_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option<PyObject> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Some(PyObject(nonnull_ptr)),
None => None,
}
}
/// Creates a `PyObject` instance for the given Python FFI pointer.
/// Calls `Py_INCREF()` on the ptr.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_borrowed_ptr(_py: Python, ptr: *mut ffi::PyObject) -> PyObject {
debug_assert!(
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
);
ffi::Py_INCREF(ptr);
PyObject(NonNull::new_unchecked(ptr))
}
/// Creates a `PyObject` instance for the given Python FFI pointer.
/// Calls `Py_INCREF()` on the ptr.
/// Returns `Err(PyErr)` if the pointer is NULL.
pub unsafe fn from_borrowed_ptr_or_err(
py: Python,
ptr: *mut ffi::PyObject,
) -> PyResult<PyObject> {
if ptr.is_null() {
Err(PyErr::fetch(py))
} else {
Ok(PyObject::from_borrowed_ptr(py, ptr))
}
}
/// Creates a `PyObject` instance for the given Python FFI pointer.
/// Calls `Py_INCREF()` on the ptr.
/// Returns `None` if the pointer is NULL.
pub unsafe fn from_borrowed_ptr_or_opt(
py: Python,
ptr: *mut ffi::PyObject,
) -> Option<PyObject> {
if ptr.is_null() {
None
} else {
Some(PyObject::from_borrowed_ptr(py, ptr))
}
}
/// Gets the reference count of the ffi::PyObject pointer.
pub fn get_refcnt(&self, _py: Python) -> isize {
unsafe { ffi::Py_REFCNT(self.0.as_ptr()) }
}
/// Clones self by calling `Py_INCREF()` on the ptr.
pub fn clone_ref(&self, py: Python) -> Self {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
/// Returns whether the object is considered to be None.
///
/// This is equivalent to the Python expression `self is None`.
pub fn is_none(&self, _py: Python) -> bool {
unsafe { ffi::Py_None() == self.as_ptr() }
}
/// Returns whether the object is considered to be true.
///
/// This is equivalent to the Python expression `bool(self)`.
pub fn is_true(&self, py: Python) -> PyResult<bool> {
let v = unsafe { ffi::PyObject_IsTrue(self.as_ptr()) };
if v == -1 {
Err(PyErr::fetch(py))
} else {
Ok(v != 0)
}
}
/// Casts the PyObject to a concrete Python object type.
///
/// This can cast only to native Python types, not types implemented in Rust.
pub fn cast_as<'p, D>(&'p self, py: Python<'p>) -> Result<&'p D, PyDowncastError>
where
D: PyTryFrom<'p>,
{
D::try_from(self.as_ref(py))
}
/// Extracts some type from the Python object.
///
/// This is a wrapper function around `FromPyObject::extract()`.
pub fn extract<'p, D>(&'p self, py: Python<'p>) -> PyResult<D>
where
D: FromPyObject<'p>,
{
FromPyObject::extract(self.as_ref(py))
}
/// Retrieves an attribute value.
///
/// This is equivalent to the Python expression `self.attr_name`.
pub fn getattr<N>(&self, py: Python, attr_name: N) -> PyResult<PyObject>
where
N: ToPyObject,
{
attr_name.with_borrowed_ptr(py, |attr_name| unsafe {
PyObject::from_owned_ptr_or_err(py, ffi::PyObject_GetAttr(self.as_ptr(), attr_name))
})
}
/// Calls the object.
///
/// This is equivalent to the Python expression `self(*args, **kwargs)`.
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))
};
unsafe {
ffi::Py_XDECREF(args);
ffi::Py_XDECREF(kwargs);
}
result
}
/// Calls the object with only positional arguments.
///
/// This is equivalent to the Python expression `self(*args)`.
pub fn call1(&self, py: Python, args: impl IntoPy<Py<PyTuple>>) -> PyResult<PyObject> {
self.call(py, args, None)
}
/// Calls the object without arguments.
///
/// This is equivalent to the Python expression `self()`.
pub fn call0(&self, py: Python) -> PyResult<PyObject> {
self.call(py, (), None)
}
/// Calls a method on the object.
///
/// This is equivalent to the Python expression `self.name(*args, **kwargs)`.
pub fn call_method(
&self,
py: Python,
name: &str,
args: impl IntoPy<Py<PyTuple>>,
kwargs: Option<&PyDict>,
) -> PyResult<PyObject> {
name.with_borrowed_ptr(py, |name| unsafe {
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() {
return Err(PyErr::fetch(py));
}
let result = PyObject::from_owned_ptr_or_err(py, ffi::PyObject_Call(ptr, args, kwargs));
ffi::Py_DECREF(ptr);
ffi::Py_XDECREF(args);
ffi::Py_XDECREF(kwargs);
result
})
}
/// Calls a method on the object with only positional arguments.
///
/// This is equivalent to the Python expression `self.name(*args)`.
pub fn call_method1(
&self,
py: Python,
name: &str,
args: impl IntoPy<Py<PyTuple>>,
) -> PyResult<PyObject> {
self.call_method(py, name, args, None)
}
/// Calls a method on the object with no arguments.
///
/// This is equivalent to the Python expression `self.name()`.
pub fn call_method0(&self, py: Python, name: &str) -> PyResult<PyObject> {
self.call_method(py, name, (), None)
}
}
impl IntoPy<PyObject> for PyObject {
fn into_py(self, _py: Python) -> PyObject {
self
}
}
impl AsPyRef for PyObject {
type Target = PyAny;
fn as_ref<'p>(&'p self, _py: Python<'p>) -> &'p PyAny {
unsafe { &*(self.as_ptr() as *const PyAny) }
}
}
impl ToPyObject for PyObject {
#[inline]
fn to_object(&self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl AsPyPointer for PyObject {
/// Gets the underlying FFI pointer, returns a borrowed pointer.
#[inline]
fn as_ptr(&self) -> *mut ffi::PyObject {
self.0.as_ptr()
}
}
impl IntoPyPointer for PyObject {
/// Gets the underlying FFI pointer, returns a owned pointer.
#[inline]
#[must_use]
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.0.as_ptr();
std::mem::forget(self); // Avoid Drop
ptr
}
}
impl PartialEq for PyObject {
/// Checks for pointer identity, not equivalent to Python's `__eq__`.
#[inline]
fn eq(&self, o: &PyObject) -> bool {
self.0 == o.0
}
}
impl<'a> FromPyObject<'a> for PyObject {
#[inline]
/// Extracts `Self` from the source `PyObject`.
fn extract(ob: &'a PyAny) -> PyResult<Self> {
unsafe { Ok(PyObject::from_borrowed_ptr(ob.py(), ob.as_ptr())) }
}
}
impl Clone for PyObject {
fn clone(&self) -> Self {
unsafe {
gil::register_incref(self.0);
}
Self(self.0)
}
}
/// Dropping a `PyObject` instance decrements the reference count on the object by 1.
impl Drop for PyObject {
fn drop(&mut self) {
unsafe {
gil::register_decref(self.0);
}
}
}
#[cfg(test)]
mod test {
use crate::types::PyDict;
use crate::PyObject;
use crate::Python;
#[test]
fn test_call_for_non_existing_method() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj: PyObject = PyDict::new(py).into();
assert!(obj.call_method0(py, "asdf").is_err());
assert!(obj
.call_method(py, "nonexistent_method", (1,), None)
.is_err());
assert!(obj.call_method0(py, "nonexistent_method").is_err());
assert!(obj.call_method1(py, "nonexistent_method", (1,)).is_err());
}
}

View File

@ -12,8 +12,8 @@
pub use crate::err::{PyErr, PyResult}; pub use crate::err::{PyErr, PyResult};
pub use crate::gil::GILGuard; pub use crate::gil::GILGuard;
pub use crate::instance::PyObject;
pub use crate::instance::{AsPyRef, Py}; pub use crate::instance::{AsPyRef, Py};
pub use crate::object::PyObject;
pub use crate::pycell::{PyCell, PyRef, PyRefMut}; pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass_init::PyClassInitializer; pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::Python; pub use crate::python::Python;

View File

@ -1,6 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors // Copyright (c) 2017-present PyO3 Project and Contributors
use crate::{ use crate::{
ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python,
ToPyObject, ToPyObject,
}; };

View File

@ -166,7 +166,7 @@ impl PyByteArray {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::exceptions; use crate::exceptions;
use crate::object::PyObject; use crate::instance::PyObject;
use crate::types::PyByteArray; use crate::types::PyByteArray;
use crate::Python; use crate::Python;

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python,
ToPyObject, ToPyObject,
}; };
use std::ops::Index; use std::ops::Index;

View File

@ -25,7 +25,7 @@ use crate::ffi::{
PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE, PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE,
PyDateTime_TIME_GET_SECOND, PyDateTime_TIME_GET_SECOND,
}; };
use crate::object::PyObject; use crate::instance::PyObject;
use crate::types::PyTuple; use crate::types::PyTuple;
use crate::{AsPyPointer, PyAny, Python, ToPyObject}; use crate::{AsPyPointer, PyAny, Python, ToPyObject};
use std::os::raw::c_int; use std::os::raw::c_int;

View File

@ -2,7 +2,7 @@
use crate::err::{self, PyErr, PyResult}; use crate::err::{self, PyErr, PyResult};
use crate::instance::PyNativeType; use crate::instance::PyNativeType;
use crate::object::PyObject; use crate::instance::PyObject;
use crate::types::{PyAny, PyList}; use crate::types::{PyAny, PyList};
#[cfg(not(PyPy))] #[cfg(not(PyPy))]
use crate::IntoPyPointer; use crate::IntoPyPointer;

View File

@ -2,7 +2,7 @@
// //
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use crate::{ use crate::{
ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python,
ToPyObject, ToPyObject,
}; };
use std::os::raw::c_double; use std::os::raw::c_double;

View File

@ -66,8 +66,17 @@ macro_rules! pyobject_native_type_named (
impl<$($type_param,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name { impl<$($type_param,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name {
#[inline] #[inline]
fn into_py(self, py: $crate::Python) -> $crate::Py<$name> { fn into_py(self, py: $crate::Python) -> $crate::Py<$name> {
use $crate::IntoPyPointer; use $crate::AsPyPointer;
unsafe { $crate::Py::from_owned_ptr(py, self.into_ptr()) } unsafe { $crate::Py::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<$($type_param,)*> From<&'_ $name> for $crate::Py<$name> {
#[inline]
fn from(other: &$name) -> Self {
use $crate::AsPyPointer;
use $crate::PyNativeType;
unsafe { $crate::Py::from_borrowed_ptr(other.py(), other.as_ptr()) }
} }
} }
}; };

View File

@ -6,7 +6,7 @@ use crate::err::{PyErr, PyResult};
use crate::exceptions; use crate::exceptions;
use crate::ffi; use crate::ffi;
use crate::instance::PyNativeType; use crate::instance::PyNativeType;
use crate::object::PyObject; use crate::instance::PyObject;
use crate::pyclass::PyClass; use crate::pyclass::PyClass;
use crate::type_object::PyTypeObject; use crate::type_object::PyTypeObject;
use crate::types::PyTuple; use crate::types::PyTuple;

View File

@ -266,9 +266,7 @@ mod int128_conversion {
#[test] #[test]
fn test_u128_overflow() { fn test_u128_overflow() {
use crate::exceptions; use crate::{exceptions, ffi, PyObject};
use crate::ffi;
use crate::object::PyObject;
use std::os::raw::c_uchar; use std::os::raw::c_uchar;
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();

View File

@ -397,7 +397,7 @@ impl<'v> PyTryFrom<'v> for PySequence {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::instance::AsPyRef; use crate::instance::AsPyRef;
use crate::object::PyObject; use crate::instance::PyObject;
use crate::types::PySequence; use crate::types::PySequence;
use crate::AsPyPointer; use crate::AsPyPointer;
use crate::Python; use crate::Python;

View File

@ -147,7 +147,7 @@ impl<'source> FromPyObject<'source> for String {
mod test { mod test {
use super::PyString; use super::PyString;
use crate::instance::AsPyRef; use crate::instance::AsPyRef;
use crate::object::PyObject; use crate::instance::PyObject;
use crate::Python; use crate::Python;
use crate::{FromPyObject, PyTryFrom, ToPyObject}; use crate::{FromPyObject, PyTryFrom, ToPyObject};

View File

@ -2,8 +2,8 @@
use crate::ffi::{self, Py_ssize_t}; use crate::ffi::{self, Py_ssize_t};
use crate::{ use crate::{
exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType,
PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, PyObject, PyResult, PyTryFrom, Python, ToPyObject,
}; };
use std::slice; use std::slice;