From f29e6bae7a241ed17d4720b29ced720225372ad3 Mon Sep 17 00:00:00 2001 From: David Hewitt <1939362+davidhewitt@users.noreply.github.com> Date: Wed, 22 Jul 2020 00:40:31 +0100 Subject: [PATCH] Replace PyObject with type alias for Py --- CHANGELOG.md | 3 + src/conversion.rs | 4 +- src/err.rs | 4 +- src/instance.rs | 234 ++++++++++++++++++++++---- src/lib.rs | 4 +- src/object.rs | 353 ---------------------------------------- src/prelude.rs | 2 +- src/types/boolobject.rs | 2 +- src/types/bytearray.rs | 2 +- src/types/bytes.rs | 2 +- src/types/datetime.rs | 2 +- src/types/dict.rs | 2 +- src/types/floatob.rs | 2 +- src/types/mod.rs | 13 +- src/types/module.rs | 2 +- src/types/num.rs | 4 +- src/types/sequence.rs | 2 +- src/types/string.rs | 2 +- src/types/tuple.rs | 4 +- 19 files changed, 232 insertions(+), 411 deletions(-) delete mode 100644 src/object.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d8aa7f..43d9feb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) - `PyType::as_type_ptr` is no longer `unsafe`. [#1047](https://github.com/PyO3/pyo3/pull/1047) - Change `PyIterator::from_object` to return `PyResult` instead of `Result`. [#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`. [#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) - 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 `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 `FromPy`. [#1063](https://github.com/PyO3/pyo3/pull/1063) ### Fixed - Conversion from types with an `__index__` method to Rust BigInts. [#1027](https://github.com/PyO3/pyo3/pull/1027) diff --git a/src/conversion.rs b/src/conversion.rs index 51569e60..e856e2b4 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -2,7 +2,7 @@ //! Conversions between various states of Rust and Python types and their wrappers. use crate::err::{self, PyDowncastError, PyResult}; -use crate::object::PyObject; +use crate::instance::PyObject; use crate::type_object::PyTypeInfo; use crate::types::PyTuple; use crate::{ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyRef, PyRefMut, Python}; @@ -383,7 +383,7 @@ where /// Converts `()` to an empty Python tuple. impl IntoPy> for () { fn into_py(self, py: Python) -> Py { - PyTuple::empty(py).into_py(py) + PyTuple::empty(py).into() } } diff --git a/src/err.rs b/src/err.rs index 110c355f..e1ade1ee 100644 --- a/src/err.rs +++ b/src/err.rs @@ -6,8 +6,8 @@ use crate::type_object::PyTypeObject; use crate::types::PyType; use crate::{exceptions, ffi}; use crate::{ - AsPyPointer, FromPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyNativeType, PyObject, - Python, ToBorrowedObject, ToPyObject, + AsPyPointer, FromPyPointer, IntoPy, IntoPyPointer, Py, PyAny, PyNativeType, PyObject, Python, + ToBorrowedObject, ToPyObject, }; use libc::c_int; use std::borrow::Cow; diff --git a/src/instance.rs b/src/instance.rs index 3052288a..7f149c4d 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,9 +1,10 @@ // 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::object::PyObject; use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell}; use crate::type_object::PyBorrowFlagLayout; +use crate::types::{PyDict, PyTuple}; use crate::{ ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject, @@ -114,6 +115,11 @@ where } impl Py { + /// For internal conversions + pub(crate) unsafe fn from_not_null(ptr: NonNull) -> Self { + Self(ptr, PhantomData) + } + /// Creates a `Py` instance for the given FFI pointer. /// /// This moves ownership over the pointer into the `Py`. @@ -187,6 +193,168 @@ impl Py { mem::forget(self); 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 { + 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 { + 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 { + 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 { + 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::(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 + 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(&self, py: Python, attr_name: N) -> PyResult + 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>, + 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)) + }; + 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>) -> PyResult { + 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 { + 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>, + kwargs: Option<&PyDict>, + ) -> PyResult { + 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>, + ) -> PyResult { + 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 { + self.call_method(py, name, (), None) + } } /// Retrieves `&'py` types from `Py` or `PyObject`. @@ -274,16 +442,25 @@ impl IntoPyPointer for Py { } } -// Native types `&T` can be converted to `Py` -impl<'a, T> std::convert::From<&'a T> for Py +impl std::convert::From<&'_ T> for PyObject where T: AsPyPointer + PyNativeType, { - fn from(obj: &'a T) -> Self { + fn from(obj: &T) -> Self { unsafe { Py::from_borrowed_ptr(obj.py(), obj.as_ptr()) } } } +impl std::convert::From> for PyObject +where + T: AsRef, +{ + fn from(other: Py) -> Self { + let Py(ptr, _) = other; + Py(ptr, PhantomData) + } +} + // `&PyCell` can be converted to `Py` impl<'a, T> std::convert::From<&PyCell> for Py where @@ -337,31 +514,6 @@ impl Drop for Py { } } -impl std::convert::From> for PyObject { - #[inline] - fn from(ob: Py) -> 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::::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::::from_borrowed_ptr(ob.py(), ob.as_ptr()) }.into() - } -} - impl<'a, T> FromPyObject<'a> for Py where T: PyTypeInfo, @@ -406,16 +558,30 @@ impl std::fmt::Debug for Py { } } +pub type PyObject = Py; + #[cfg(test)] mod test { - use super::Py; - use crate::ffi; + use super::{Py, PyObject}; 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] fn py_from_dict() { - let dict = { + let dict: Py = { let gil = Python::acquire_gil(); let py = gil.python(); let native = PyDict::new(py); diff --git a/src/lib.rs b/src/lib.rs index d6ff5a47..25638145 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,8 +140,7 @@ pub use crate::conversion::{ }; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult}; pub use crate::gil::{GILGuard, GILPool}; -pub use crate::instance::{AsPyRef, Py, PyNativeType}; -pub use crate::object::PyObject; +pub use crate::instance::{AsPyRef, Py, PyNativeType, PyObject}; pub use crate::pycell::{PyCell, PyRef, PyRefMut}; pub use crate::pyclass::PyClass; pub use crate::pyclass_init::PyClassInitializer; @@ -184,7 +183,6 @@ mod instance; #[macro_use] mod internal_tricks; pub mod marshal; -mod object; pub mod once_cell; pub mod panic; pub mod prelude; diff --git a/src/object.rs b/src/object.rs deleted file mode 100644 index 10606859..00000000 --- a/src/object.rs +++ /dev/null @@ -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`. -#[derive(Debug)] -#[repr(transparent)] -pub struct PyObject(NonNull); - -// `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) -> 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 { - 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 { - 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 { - 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 { - 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 { - 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 - 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(&self, py: Python, attr_name: N) -> PyResult - 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>, - 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)) - }; - 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>) -> PyResult { - 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 { - 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>, - kwargs: Option<&PyDict>, - ) -> PyResult { - 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>, - ) -> PyResult { - 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 { - self.call_method(py, name, (), None) - } -} - -impl IntoPy 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 { - 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()); - } -} diff --git a/src/prelude.rs b/src/prelude.rs index 343969cd..eeb828ea 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -12,8 +12,8 @@ pub use crate::err::{PyErr, PyResult}; pub use crate::gil::GILGuard; +pub use crate::instance::PyObject; pub use crate::instance::{AsPyRef, Py}; -pub use crate::object::PyObject; pub use crate::pycell::{PyCell, PyRef, PyRefMut}; pub use crate::pyclass_init::PyClassInitializer; pub use crate::python::Python; diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index 32373792..1853631b 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,6 +1,6 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::{ - ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, + ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, }; diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 1609ece9..3ae22d49 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -166,7 +166,7 @@ impl PyByteArray { #[cfg(test)] mod test { use crate::exceptions; - use crate::object::PyObject; + use crate::instance::PyObject; use crate::types::PyByteArray; use crate::Python; diff --git a/src/types/bytes.rs b/src/types/bytes.rs index 540c5233..18eb180e 100644 --- a/src/types/bytes.rs +++ b/src/types/bytes.rs @@ -1,5 +1,5 @@ use crate::{ - ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python, + ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python, ToPyObject, }; use std::ops::Index; diff --git a/src/types/datetime.rs b/src/types/datetime.rs index 6e035c11..c38063cf 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -25,7 +25,7 @@ use crate::ffi::{ PyDateTime_TIME_GET_HOUR, PyDateTime_TIME_GET_MICROSECOND, PyDateTime_TIME_GET_MINUTE, PyDateTime_TIME_GET_SECOND, }; -use crate::object::PyObject; +use crate::instance::PyObject; use crate::types::PyTuple; use crate::{AsPyPointer, PyAny, Python, ToPyObject}; use std::os::raw::c_int; diff --git a/src/types/dict.rs b/src/types/dict.rs index 66d157c2..1b6f9d52 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -2,7 +2,7 @@ use crate::err::{self, PyErr, PyResult}; use crate::instance::PyNativeType; -use crate::object::PyObject; +use crate::instance::PyObject; use crate::types::{PyAny, PyList}; #[cfg(not(PyPy))] use crate::IntoPyPointer; diff --git a/src/types/floatob.rs b/src/types/floatob.rs index 7e65e995..d8ed22c5 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -2,7 +2,7 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use crate::{ - ffi, AsPyPointer, IntoPy, FromPyObject, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, + ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject, }; use std::os::raw::c_double; diff --git a/src/types/mod.rs b/src/types/mod.rs index 493b87bd..32bbfe8e 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -66,8 +66,17 @@ macro_rules! pyobject_native_type_named ( impl<$($type_param,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name { #[inline] fn into_py(self, py: $crate::Python) -> $crate::Py<$name> { - use $crate::IntoPyPointer; - unsafe { $crate::Py::from_owned_ptr(py, self.into_ptr()) } + use $crate::AsPyPointer; + 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()) } } } }; diff --git a/src/types/module.rs b/src/types/module.rs index 21e95f8b..ede21ff0 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -6,7 +6,7 @@ use crate::err::{PyErr, PyResult}; use crate::exceptions; use crate::ffi; use crate::instance::PyNativeType; -use crate::object::PyObject; +use crate::instance::PyObject; use crate::pyclass::PyClass; use crate::type_object::PyTypeObject; use crate::types::PyTuple; diff --git a/src/types/num.rs b/src/types/num.rs index 3a37f703..e41a8269 100644 --- a/src/types/num.rs +++ b/src/types/num.rs @@ -266,9 +266,7 @@ mod int128_conversion { #[test] fn test_u128_overflow() { - use crate::exceptions; - use crate::ffi; - use crate::object::PyObject; + use crate::{exceptions, ffi, PyObject}; use std::os::raw::c_uchar; let gil = Python::acquire_gil(); let py = gil.python(); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 51f8bbb0..1831f3eb 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -397,7 +397,7 @@ impl<'v> PyTryFrom<'v> for PySequence { #[cfg(test)] mod test { use crate::instance::AsPyRef; - use crate::object::PyObject; + use crate::instance::PyObject; use crate::types::PySequence; use crate::AsPyPointer; use crate::Python; diff --git a/src/types/string.rs b/src/types/string.rs index c8f4a826..580cdf43 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -147,7 +147,7 @@ impl<'source> FromPyObject<'source> for String { mod test { use super::PyString; use crate::instance::AsPyRef; - use crate::object::PyObject; + use crate::instance::PyObject; use crate::Python; use crate::{FromPyObject, PyTryFrom, ToPyObject}; diff --git a/src/types/tuple.rs b/src/types/tuple.rs index 92e7fc8c..36fed55b 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -2,8 +2,8 @@ use crate::ffi::{self, Py_ssize_t}; use crate::{ - exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, - PyNativeType, PyObject, PyResult, PyTryFrom, Python, ToPyObject, + exceptions, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, Py, PyAny, PyErr, PyNativeType, + PyObject, PyResult, PyTryFrom, Python, ToPyObject, }; use std::slice;