Merge pull request #1063 from davidhewitt/remove-pyobject

Make `PyObject` a type alias of `Py<PyAny>` (& remove `FromPy`)
This commit is contained in:
David Hewitt 2020-08-09 22:06:49 +01:00 committed by GitHub
commit bcb90775b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 488 additions and 643 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)
- `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)
- `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)
- 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)

View File

@ -44,13 +44,13 @@ The table below contains the Python type and the corresponding function argument
There are also a few special types related to the GIL and Rust-defined `#[pyclass]`es which may come in useful:
| What | Description |
| ------------- | ------------------------------- |
| ------------- | ------------------------------------- |
| `Python` | A GIL token, used to pass to PyO3 constructors to prove ownership of the GIL |
| `PyObject` | A Python object isolated from the GIL lifetime. This can be sent to other threads. To call Python APIs using this object, it must be used with `AsPyRef::as_ref` to get a `&PyAny` reference. |
| `Py<T>` | Same as above, for a specific Python type or `#[pyclass]` T. |
| `Py<T>` | A Python object isolated from the GIL lifetime. This can be sent to other threads. To call Python APIs using this object, it must be used with `AsPyRef::as_ref` to get an `&T` reference bound to the GIL. |
| `PyObject` | An alias for `Py<PyAny>` |
| `&PyCell<T>` | A `#[pyclass]` value owned by Python. |
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |
| `PyRefMut<T>` | A `#[pyclass]` borrowed mutably. |
| `PyRef<T>` | A `#[pyclass]` borrowed immutably. |
| `PyRefMut<T>` | A `#[pyclass]` borrowed mutably. |
For more detail on accepting `#[pyclass]` values as function arguments, see [the section of this guide on Python Classes](class.md).
@ -119,6 +119,28 @@ mutable references, you have to extract the PyO3 reference wrappers [`PyRef`]
and [`PyRefMut`]. They work like the reference wrappers of
`std::cell::RefCell` and ensure (at runtime) that Rust borrows are allowed.
### `IntoPy<T>`
This trait defines the to-python conversion for a Rust type. It is usually implemented as
`IntoPy<PyObject>`, which is the trait needed for returning a value from `#[pyfunction]` and
`#[pymethods]`.
All types in PyO3 implement this trait, as does a `#[pyclass]` which doesn't use `extends`.
Occasionally you may choose to implement this for custom types which are mapped to Python types
_without_ having a unique python type.
```
use pyo3::prelude::*;
struct MyPyObjectWrapper(PyObject);
impl IntoPy<PyObject> for MyPyObjectWrapper {
fn into_py(self, py: Python) -> PyObject {
self.0
}
}
```
### The `ToPyObject` trait
@ -216,22 +238,10 @@ fn main() {
}
```
### `FromPy<T>` and `IntoPy<T>`
Many conversions in PyO3 can't use `std::convert::From` because they need a GIL token.
The [`FromPy`] trait offers an `from_py` method that works just like `from`, except for taking a `Python<'_>` argument.
I.e. `FromPy<T>` could be converting a Rust object into a Python object even though it is called [`FromPy`] - it doesn't say anything about which side of the conversion is a Python object.
Just like `From<T>`, if you implement `FromPy<T>` you gain a blanket implementation of [`IntoPy`] for free.
Eventually, traits such as [`ToPyObject`] will be replaced by this trait and a [`FromPy`] trait will be added that will implement
[`IntoPy`], just like with `From` and `Into`.
[`IntoPy`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.IntoPy.html
[`FromPy`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.FromPy.html
[`FromPyObject`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.FromPyObject.html
[`ToPyObject`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.ToPyObject.html
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/type.PyObject.html
[`PyTuple`]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyTuple.html
[`PyAny`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html
[`IntoPyDict`]: https://docs.rs/pyo3/latest/pyo3/types/trait.IntoPyDict.html

View File

@ -192,15 +192,12 @@ mod io {
pyo3::import_exception!(io, UnsupportedOperation);
}
fn tell(file: PyObject) -> PyResult<u64> {
fn tell(file: &PyAny) -> PyResult<u64> {
use pyo3::exceptions::*;
let gil = Python::acquire_gil();
let py = gil.python();
match file.call_method0(py, "tell") {
match file.call_method0("tell") {
Err(_) => Err(io::UnsupportedOperation::py_err("not supported: tell")),
Ok(x) => x.extract::<u64>(py),
Ok(x) => x.extract::<u64>(),
}
}

View File

@ -187,5 +187,5 @@ If you have a static function, you can expose it with `#[pyfunction]` and use [`
[`PyAny::call`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call
[`PyAny::call0`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call0
[`PyAny::call1`]: https://docs.rs/pyo3/latest/pyo3/struct.PyAny.html#tymethod.call1
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/type.PyObject.html
[`wrap_pyfunction!`]: https://docs.rs/pyo3/latest/pyo3/macro.wrap_pyfunction.html

View File

@ -3,6 +3,65 @@
This guide can help you upgrade code through breaking changes from one PyO3 version to the next.
For a detailed list of all changes, see [CHANGELOG.md](https://github.com/PyO3/pyo3/blob/master/CHANGELOG.md)
## from 0.11.* to 0.12
### `FromPy` has been removed
To simplify the PyO3 public conversion trait hierarchy, the `FromPy` has been removed. In PyO3
`0.11` there were two ways to define the to-Python conversion for a type: `FromPy<T> for PyObject`,
and `IntoPy<PyObject> for T`.
Now, the canonical implementation is always `IntoPy`, so downstream crates may need to adjust
accordingly.
Before:
```rust,ignore
# use pyo3::prelude::*;
struct MyPyObjectWrapper(PyObject);
impl FromPy<MyPyObjectWrapper> for PyObject {
fn from_py(other: MyPyObjectWrapper, _py: Python) -> Self {
other.0
}
}
```
After
```rust
# use pyo3::prelude::*;
struct MyPyObjectWrapper(PyObject);
impl IntoPy<PyObject> for MyPyObjectWrapper {
fn into_py(self, _py: Python) -> PyObject {
self.0
}
}
```
Similarly, code which was using the `FromPy` trait can be trivially rewritten to use `IntoPy`.
Before:
```rust,ignore
# use pyo3::prelude::*;
# Python::with_gil(|py| {
let obj = PyObject::from_py(1.234, py);
# })
```
After:
```rust
# use pyo3::prelude::*;
# Python::with_gil(|py| {
let obj: PyObject = 1.234.into_py(py);
# })
```
### `PyObject` is now a type alias of `Py<PyAny>`
This should change very little from a usage perspective. If you implemented traits for both
`PyObject` and `Py<T>`, you may find you can just remove the `PyObject` implementation.
## from 0.10.* to 0.11
### Stable Rust

View File

@ -24,7 +24,7 @@ In PyO3, holding the GIL is modeled by acquiring a token of the type
* It provides some global API for the Python interpreter, such as
[`eval`][eval].
* It can be passed to functions that require a proof of holding the GIL,
such as [`PyObject::clone_ref`][clone_ref].
such as [`Py::clone_ref`][clone_ref].
* Its lifetime can be used to create Rust references that implicitly guarantee
holding the GIL, such as [`&'py PyAny`][PyAny].
@ -71,10 +71,7 @@ let obj: &PyAny = PyList::empty(py);
// Convert to &ConcreteType using PyAny::downcast
let _: &PyList = obj.downcast().unwrap();
// Convert to PyObject using .into() or .to_object(py)
let _: PyObject = obj.into();
// Convert to Py<PyAny> using .into() or Py::from
// Convert to Py<PyAny> (aka PyObject) using .into()
let _: Py<PyAny> = obj.into();
// Convert to Py<ConcreteType> using PyAny::extract
@ -115,51 +112,24 @@ let _: &PyAny = list;
// For more explicit &PyAny conversion, use .as_ref()
let _: &PyAny = list.as_ref();
// To convert to PyObject use .into() or .to_object(py)
let _: PyObject = list.into();
// To convert to Py<T> use .into() or Py::from()
let _: Py<PyList> = list.into();
// To convert to PyObject use .into() or .to_object(py)
let _: PyObject = list.into();
```
### `PyObject`
### `Py<T>`
**Represents:** a GIL independent reference to a Python object of unspecified
type.
**Represents:** a GIL independent reference to a Python object. This can be a Python native type
(like `PyTuple`), or a `pyclass` type implemented in Rust. The most commonly-used variant,
`Py<PyAny>`, is also known as `PyObject`.
**Used:** Whenever you want to carry around references to "some" Python object,
without caring about a GIL lifetime. For example, storing Python object
references in a Rust struct that outlives the Python-Rust FFI boundary,
or returning objects from functions implemented in Rust back to Python.
**Used:** Whenever you want to carry around references to a Python object without caring about a
GIL lifetime. For example, storing Python object references in a Rust struct that outlives the
Python-Rust FFI boundary, or returning objects from functions implemented in Rust back to Python.
Can be cloned using Python reference counts with `.clone_ref()`.
**Conversions:**
```rust
# use pyo3::prelude::*;
# use pyo3::types::PyList;
# let gil = Python::acquire_gil();
# let py = gil.python();
let obj: PyObject = PyList::empty(py).into();
// Convert to &PyAny using AsPyRef::as_ref
let _: &PyAny = obj.as_ref(py);
// Convert to &ConcreteType using PyObject::cast_as
let _: &PyList = obj.cast_as(py).unwrap();
// Convert to Py<ConcreteType> using PyObject::extract
let _: Py<PyList> = obj.extract(py).unwrap();
```
### `Py<SomeType>`
**Represents:** a GIL independent reference to a Python object of known type.
This can be a Python native type (like `PyTuple`), or a `pyclass` type
implemented in Rust.
**Used:** Like `PyObject`, but with a known inner type.
Can be cloned using Python reference counts with `.clone()`.
**Conversions:**
@ -178,10 +148,6 @@ let _: &PyList = list.as_ref(py);
let _: PyObject = list.into();
```
**Note:** `PyObject` is semantically equivalent to `Py<PyAny>` and might be
merged with it in the future.
### `PyCell<SomeType>`
**Represents:** a reference to a Rust object (instance of `PyClass`) which is
@ -248,7 +214,7 @@ This trait marks structs that mirror native Python types, such as `PyList`.
[eval]: https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.eval
[clone_ref]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html#method.clone_ref
[clone_ref]: https://docs.rs/pyo3/latest/pyo3/struct.Py.html#method.clone_ref
[pyo3::types]: https://docs.rs/pyo3/latest/pyo3/types/index.html
[PyAny]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyAny.html
[PyList_append]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyList.html#method.append

View File

@ -190,7 +190,7 @@ pub fn add_fn_to_module(
};
let function = unsafe {
pyo3::PyObject::from_owned_ptr_or_panic(
pyo3::PyObject::from_owned_ptr(
py,
pyo3::ffi::PyCFunction_New(
Box::into_raw(Box::new(_def.as_method_def())),

View File

@ -2,10 +2,11 @@
//! Conversions between various states of Rust and Python types and their wrappers.
use crate::err::{self, PyDowncastError, PyResult};
use crate::object::PyObject;
use crate::type_object::PyTypeInfo;
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, PyObject, PyRef, PyRefMut, Python,
};
use std::ptr::NonNull;
/// This trait represents that **we can do zero-cost conversion from the object
@ -132,42 +133,22 @@ where
}
}
/// Similar to [std::convert::From], just that it requires a gil token.
pub trait FromPy<T>: Sized {
/// Performs the conversion.
fn from_py(_: T, py: Python) -> Self;
}
/// Similar to [std::convert::Into], just that it requires a gil token.
///
/// `IntoPy<PyObject>` (aka `IntoPy<Py<PyAny>>`) should be implemented to define a conversion from
/// Rust to Python which can be used by most of PyO3's methods.
pub trait IntoPy<T>: Sized {
/// Performs the conversion.
fn into_py(self, py: Python) -> T;
}
// From implies Into
impl<T, U> IntoPy<U> for T
where
U: FromPy<T>,
{
fn into_py(self, py: Python) -> U {
U::from_py(self, py)
}
}
// From (and thus Into) is reflexive
impl<T> FromPy<T> for T {
fn from_py(t: T, _: Python) -> T {
t
}
}
/// `FromPyObject` is implemented by various types that can be extracted from
/// a Python object reference.
///
/// Normal usage is through the helper methods `PyObject::extract` or
/// `PyAny::extract`:
/// Normal usage is through the helper methods `Py::extract` or `PyAny::extract`:
///
/// ```let obj: PyObject = ...;
/// ```rust,ignore
/// let obj: Py<PyAny> = ...;
/// let value: &TargetType = obj.extract(py)?;
///
/// let any: &PyAny = ...;
@ -184,9 +165,6 @@ impl<T> FromPy<T> for T {
/// Since which case applies depends on the runtime type of the Python object,
/// both the `obj` and `prepared` variables must outlive the resulting string slice.
///
/// In cases where the result does not depend on the `'prepared` lifetime,
/// the inherent method `PyObject::extract()` can be used.
///
/// The trait's conversion method takes a `&PyAny` argument but is called
/// `FromPyObject` for historical reasons.
pub trait FromPyObject<'source>: Sized {
@ -234,19 +212,19 @@ impl ToPyObject for () {
}
}
impl FromPy<()> for PyObject {
fn from_py(_: (), py: Python) -> Self {
impl IntoPy<PyObject> for () {
fn into_py(self, py: Python) -> PyObject {
py.None()
}
}
impl<'a, T> FromPy<&'a T> for PyObject
impl<T> IntoPy<PyObject> for &'_ T
where
T: AsPyPointer,
{
#[inline]
fn from_py(other: &'a T, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, other.as_ptr()) }
fn into_py(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
@ -404,9 +382,9 @@ where
}
/// Converts `()` to an empty Python tuple.
impl FromPy<()> for Py<PyTuple> {
fn from_py(_: (), py: Python) -> Py<PyTuple> {
Py::from_py(PyTuple::empty(py), py)
impl IntoPy<Py<PyTuple>> for () {
fn into_py(self, py: Python) -> Py<PyTuple> {
PyTuple::empty(py).into()
}
}

View File

@ -6,8 +6,8 @@ use crate::type_object::PyTypeObject;
use crate::types::PyType;
use crate::{exceptions, ffi};
use crate::{
AsPyPointer, FromPy, 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;
@ -438,15 +438,15 @@ impl std::fmt::Debug for PyErr {
}
}
impl FromPy<PyErr> for PyObject {
fn from_py(other: PyErr, py: Python) -> Self {
other.instance(py).into()
impl IntoPy<PyObject> for PyErr {
fn into_py(self, py: Python) -> PyObject {
self.instance(py).into()
}
}
impl FromPy<PyErr> for Py<exceptions::PyBaseException> {
fn from_py(other: PyErr, py: Python) -> Self {
other.instance(py).into()
impl IntoPy<Py<exceptions::PyBaseException>> for PyErr {
fn into_py(self, py: Python) -> Py<exceptions::PyBaseException> {
self.instance(py).into()
}
}

View File

@ -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,59 +115,6 @@ where
}
impl<T> Py<T> {
/// Creates a `Py<T>` instance for the given FFI pointer.
///
/// This moves ownership over the pointer into the `Py<T>`.
/// Undefined behavior if the pointer is NULL or invalid.
#[inline]
pub unsafe fn from_owned_ptr(_py: Python, ptr: *mut ffi::PyObject) -> Py<T> {
debug_assert!(
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
);
Py(NonNull::new_unchecked(ptr), PhantomData)
}
/// Creates a `Py<T>` 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) -> Py<T> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Py(nonnull_ptr, PhantomData),
None => {
crate::err::panic_after_error(_py);
}
}
}
/// Construct `Py<T>` from the result of a Python FFI call that
///
/// Returns a new reference (owned pointer).
/// Returns `Err(PyErr)` if the pointer is NULL.
/// Unsafe because the pointer might be invalid.
pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Py<T>> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Ok(Py(nonnull_ptr, PhantomData)),
None => Err(PyErr::fetch(py)),
}
}
/// Creates a `Py<T>` 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) -> Py<T> {
debug_assert!(
!ptr.is_null() && ffi::Py_REFCNT(ptr) > 0,
format!("REFCNT: {:?} - {:?}", ptr, ffi::Py_REFCNT(ptr))
);
ffi::Py_INCREF(ptr);
Py(NonNull::new_unchecked(ptr), PhantomData)
}
/// Gets the reference count of the `ffi::PyObject` pointer.
#[inline]
pub fn get_refcnt(&self, _py: Python) -> isize {
@ -179,10 +127,228 @@ impl<T> Py<T> {
unsafe { Py::from_borrowed_ptr(py, self.0.as_ptr()) }
}
/// Returns the inner pointer without decreasing the refcount.
/// Returns whether the object is considered to be None.
///
/// This will eventually move into its own trait.
pub(crate) fn into_non_null(self) -> NonNull<ffi::PyObject> {
/// 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)
}
}
/// 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)
}
/// Create a `Py<T>` instance by taking ownership of the given FFI pointer.
///
/// # Safety
/// `ptr` must be a pointer to a Python object of type T.
///
/// # Panics
/// Panics if `ptr` is null.
#[inline]
pub unsafe fn from_owned_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<T> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Py(nonnull_ptr, PhantomData),
None => crate::err::panic_after_error(py),
}
}
/// Deprecated alias for [`from_owned_ptr`](#method.from_owned_ptr).
#[inline]
#[deprecated = "this is a deprecated alias for Py::from_owned_ptr"]
pub unsafe fn from_owned_ptr_or_panic(py: Python, ptr: *mut ffi::PyObject) -> Py<T> {
Py::from_owned_ptr(py, ptr)
}
/// Create a `Py<T>` instance by taking ownership of the given FFI pointer.
///
/// If `ptr` is null then the current Python exception is fetched as a `PyErr`.
///
/// # Safety
/// If non-null, `ptr` must be a pointer to a Python object of type T.
#[inline]
pub unsafe fn from_owned_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Py<T>> {
match NonNull::new(ptr) {
Some(nonnull_ptr) => Ok(Py(nonnull_ptr, PhantomData)),
None => Err(PyErr::fetch(py)),
}
}
/// Create a `Py<T>` instance by taking ownership of the given FFI pointer.
///
/// If `ptr` is null then `None` is returned.
///
/// # Safety
/// If non-null, `ptr` must be a pointer to a Python object of type T.
#[inline]
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,
}
}
/// Create a `Py<T>` instance by creating a new reference from the given FFI pointer.
///
/// # Safety
/// `ptr` must be a pointer to a Python object of type T.
///
/// # Panics
/// Panics if `ptr` is null.
#[inline]
pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut ffi::PyObject) -> Py<T> {
match Self::from_borrowed_ptr_or_opt(py, ptr) {
Some(slf) => slf,
None => crate::err::panic_after_error(py),
}
}
/// Create a `Py<T>` instance by creating a new reference from the given FFI pointer.
///
/// If `ptr` is null then the current Python exception is fetched as a `PyErr`.
///
/// # Safety
/// `ptr` must be a pointer to a Python object of type T.
#[inline]
pub unsafe fn from_borrowed_ptr_or_err(py: Python, ptr: *mut ffi::PyObject) -> PyResult<Self> {
Self::from_borrowed_ptr_or_opt(py, ptr).ok_or_else(|| PyErr::fetch(py))
}
/// Create a `Py<T>` instance by creating a new reference from the given FFI pointer.
///
/// If `ptr` is null then `None` is returned.
///
/// # Safety
/// `ptr` must be a pointer to a Python object of type T.
#[inline]
pub unsafe fn from_borrowed_ptr_or_opt(_py: Python, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|nonnull_ptr| {
ffi::Py_INCREF(ptr);
Py(nonnull_ptr, PhantomData)
})
}
/// For internal conversions.
///
/// # Safety
/// `ptr` must point to a Python object of type T.
#[inline]
unsafe fn from_non_null(ptr: NonNull<ffi::PyObject>) -> Self {
Self(ptr, PhantomData)
}
/// Returns the inner pointer without decreasing the refcount.
#[inline]
fn into_non_null(self) -> NonNull<ffi::PyObject> {
let pointer = self.0;
mem::forget(self);
pointer
@ -253,7 +419,7 @@ impl<T> IntoPy<PyObject> for Py<T> {
/// Consumes `self` without calling `Py_DECREF()`.
#[inline]
fn into_py(self, _py: Python) -> PyObject {
unsafe { PyObject::from_not_null(self.into_non_null()) }
unsafe { PyObject::from_non_null(self.into_non_null()) }
}
}
@ -274,16 +440,25 @@ impl<T> IntoPyPointer for Py<T> {
}
}
// Native types `&T` can be converted to `Py<T>`
impl<'a, T> std::convert::From<&'a T> for Py<T>
impl<T> 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<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>`
impl<'a, T> std::convert::From<&PyCell<T>> for Py<T>
where
@ -337,31 +512,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>
where
T: PyTypeInfo,
@ -406,16 +556,49 @@ impl<T> std::fmt::Debug for Py<T> {
}
}
/// A commonly-used alias for `Py<PyAny>`.
///
/// This is an owned reference a Python object without any type information. This value can also be
/// safely sent between threads.
///
/// See the documentation for [`Py`](struct.Py.html).
pub type PyObject = Py<PyAny>;
impl PyObject {
/// Casts the PyObject to a concrete Python object type.
///
/// This can cast only to native Python types, not types implemented in Rust. For a more
/// flexible alternative, see [`Py::extract`](struct.Py.html#method.extract).
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()) })
}
}
#[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<PyDict> = {
let gil = Python::acquire_gil();
let py = gil.python();
let native = PyDict::new(py);

View File

@ -135,13 +135,12 @@
pub use crate::class::*;
pub use crate::conversion::{
AsPyPointer, FromPy, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto,
AsPyPointer, FromPyObject, FromPyPointer, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto,
ToBorrowedObject, ToPyObject,
};
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;

View File

@ -1,347 +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 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,12 +12,11 @@
pub use crate::err::{PyErr, PyResult};
pub use crate::gil::GILGuard;
pub use crate::instance::{AsPyRef, Py};
pub use crate::object::PyObject;
pub use crate::instance::{AsPyRef, Py, PyObject};
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
pub use crate::pyclass_init::PyClassInitializer;
pub use crate::python::Python;
pub use crate::{FromPy, FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto, ToPyObject};
pub use crate::{FromPyObject, IntoPy, IntoPyPointer, PyTryFrom, PyTryInto, ToPyObject};
// PyModule is only part of the prelude because we need it for the pymodule function
pub use crate::types::{PyAny, PyModule};
#[cfg(feature = "macros")]

View File

@ -6,7 +6,7 @@ use crate::pyclass_init::PyClassInitializer;
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{PyBorrowFlagLayout, PyLayout, PySizedLayout, PyTypeInfo};
use crate::types::PyAny;
use crate::{ffi, FromPy, PyErr, PyNativeType, PyObject, PyResult, Python};
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
use std::cell::{Cell, UnsafeCell};
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
@ -572,9 +572,9 @@ impl<'p, T: PyClass> Drop for PyRef<'p, T> {
}
}
impl<'p, T: PyClass> FromPy<PyRef<'p, T>> for PyObject {
fn from_py(pyref: PyRef<'p, T>, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) }
impl<T: PyClass> IntoPy<PyObject> for PyRef<'_, T> {
fn into_py(self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
}
}
@ -670,9 +670,9 @@ impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
}
}
impl<'p, T: PyClass> FromPy<PyRefMut<'p, T>> for PyObject {
fn from_py(pyref: PyRefMut<'p, T>, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, pyref.inner.as_ptr()) }
impl<T: PyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
fn into_py(self, py: Python) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
}
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::{
ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python,
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python,
ToPyObject,
};
@ -41,10 +41,10 @@ impl ToPyObject for bool {
}
}
impl FromPy<bool> for PyObject {
impl IntoPy<PyObject> for bool {
#[inline]
fn from_py(other: bool, py: Python) -> Self {
PyBool::new(py, other).into()
fn into_py(self, py: Python) -> PyObject {
PyBool::new(py, self).into()
}
}

View File

@ -166,9 +166,8 @@ impl PyByteArray {
#[cfg(test)]
mod test {
use crate::exceptions;
use crate::object::PyObject;
use crate::types::PyByteArray;
use crate::Python;
use crate::{PyObject, Python};
#[test]
fn test_len() {

View File

@ -1,5 +1,5 @@
use crate::{
ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyObject, PyResult, PyTryFrom, Python,
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyObject, PyResult, PyTryFrom, Python,
ToPyObject,
};
use std::ops::Index;
@ -93,9 +93,9 @@ impl<I: SliceIndex<[u8]>> Index<I> for PyBytes {
}
}
impl<'a> FromPy<&'a [u8]> for PyObject {
fn from_py(other: &'a [u8], py: Python) -> Self {
PyBytes::new(py, other).to_object(py)
impl<'a> IntoPy<PyObject> for &'a [u8] {
fn into_py(self, py: Python) -> PyObject {
PyBytes::new(py, self).to_object(py)
}
}

View File

@ -149,7 +149,7 @@ mod complex_conversion {
unsafe {
let raw_obj =
ffi::PyComplex_FromDoubles(self.re as c_double, self.im as c_double);
PyObject::from_owned_ptr_or_panic(py, raw_obj)
PyObject::from_owned_ptr(py, raw_obj)
}
}
}

View File

@ -25,9 +25,8 @@ 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::types::PyTuple;
use crate::{AsPyPointer, PyAny, Python, ToPyObject};
use crate::{AsPyPointer, PyAny, PyObject, Python, ToPyObject};
use std::os::raw::c_int;
#[cfg(not(PyPy))]
use std::ptr;

View File

@ -1,13 +1,12 @@
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::err::{self, PyErr, PyResult};
use crate::instance::PyNativeType;
use crate::object::PyObject;
use crate::types::{PyAny, PyList};
#[cfg(not(PyPy))]
use crate::IntoPyPointer;
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, PyTryFrom, Python, ToBorrowedObject, ToPyObject,
ffi, AsPyPointer, FromPyObject, IntoPy, PyNativeType, PyObject, PyTryFrom, Python,
ToBorrowedObject, ToPyObject,
};
use std::collections::{BTreeMap, HashMap};
use std::ptr::NonNull;

View File

@ -2,7 +2,7 @@
//
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
use crate::{
ffi, AsPyPointer, FromPy, FromPyObject, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python,
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python,
ToPyObject,
};
use std::os::raw::c_double;
@ -11,7 +11,7 @@ use std::os::raw::c_double;
///
/// You can usually avoid directly working with this type
/// by using [`ToPyObject`](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// and [extract](struct.PyAny.html#method.extract)
/// with `f32`/`f64`.
#[repr(transparent)]
pub struct PyFloat(PyAny);
@ -41,9 +41,9 @@ impl ToPyObject for f64 {
}
}
impl FromPy<f64> for PyObject {
fn from_py(other: f64, py: Python) -> Self {
PyFloat::new(py, other).into()
impl IntoPy<PyObject> for f64 {
fn into_py(self, py: Python) -> PyObject {
PyFloat::new(py, self).into()
}
}
@ -67,9 +67,9 @@ impl ToPyObject for f32 {
}
}
impl FromPy<f32> for PyObject {
fn from_py(other: f32, py: Python) -> Self {
PyFloat::new(py, f64::from(other)).into()
impl IntoPy<PyObject> for f32 {
fn into_py(self, py: Python) -> PyObject {
PyFloat::new(py, f64::from(self)).into()
}
}

View File

@ -173,7 +173,7 @@ where
let obj = e.to_object(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
PyObject::from_owned_ptr_or_panic(py, ptr)
PyObject::from_owned_ptr(py, ptr)
}
}
}
@ -218,7 +218,7 @@ where
let obj = e.into_py(py).into_ptr();
ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj);
}
PyObject::from_owned_ptr_or_panic(py, ptr)
PyObject::from_owned_ptr(py, ptr)
}
}
}

View File

@ -62,6 +62,23 @@ macro_rules! pyobject_native_type_named (
self.as_ptr() == o.as_ptr()
}
}
impl<$($type_param,)*> $crate::IntoPy<$crate::Py<$name>> for &'_ $name {
#[inline]
fn into_py(self, py: $crate::Python) -> $crate::Py<$name> {
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()) }
}
}
};
);

View File

@ -6,12 +6,11 @@ use crate::err::{PyErr, PyResult};
use crate::exceptions;
use crate::ffi;
use crate::instance::PyNativeType;
use crate::object::PyObject;
use crate::pyclass::PyClass;
use crate::type_object::PyTypeObject;
use crate::types::PyTuple;
use crate::types::{PyAny, PyDict, PyList};
use crate::{AsPyPointer, IntoPy, Py, Python, ToPyObject};
use crate::{AsPyPointer, IntoPy, Py, PyObject, Python, ToPyObject};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::str;

View File

@ -50,7 +50,7 @@ macro_rules! int_fits_larger_int {
///
/// You can usually avoid directly working with this type
/// by using [`ToPyObject`](trait.ToPyObject.html)
/// and [extract](struct.PyObject.html#method.extract)
/// and [extract](struct.PyAny.html#method.extract)
/// with the primitive Rust integer types.
#[repr(transparent)]
pub struct PyLong(PyAny);
@ -62,17 +62,13 @@ macro_rules! int_fits_c_long {
impl ToPyObject for $rust_type {
#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
fn to_object(&self, py: Python) -> PyObject {
unsafe {
PyObject::from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(*self as c_long))
}
unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(*self as c_long)) }
}
}
impl IntoPy<PyObject> for $rust_type {
#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
fn into_py(self, py: Python) -> PyObject {
unsafe {
PyObject::from_owned_ptr_or_panic(py, ffi::PyLong_FromLong(self as c_long))
}
unsafe { PyObject::from_owned_ptr(py, ffi::PyLong_FromLong(self as c_long)) }
}
}
@ -101,13 +97,13 @@ macro_rules! int_convert_u64_or_i64 {
impl ToPyObject for $rust_type {
#[inline]
fn to_object(&self, py: Python) -> PyObject {
unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(*self)) }
unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(*self)) }
}
}
impl IntoPy<PyObject> for $rust_type {
#[inline]
fn into_py(self, py: Python) -> PyObject {
unsafe { PyObject::from_owned_ptr_or_panic(py, $pylong_from_ll_or_ull(self)) }
unsafe { PyObject::from_owned_ptr(py, $pylong_from_ll_or_ull(self)) }
}
}
impl<'source> FromPyObject<'source> for $rust_type {
@ -194,7 +190,7 @@ mod int128_conversion {
IS_LITTLE_ENDIAN,
$is_signed,
);
PyObject::from_owned_ptr_or_panic(py, obj)
PyObject::from_owned_ptr(py, obj)
}
}
}
@ -266,9 +262,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();
@ -280,7 +274,7 @@ mod int128_conversion {
super::IS_LITTLE_ENDIAN,
0,
);
let obj = PyObject::from_owned_ptr_or_panic(py, obj);
let obj = PyObject::from_owned_ptr(py, obj);
let err = obj.extract::<u128>(py).unwrap_err();
assert!(err.is_instance::<exceptions::PyOverflowError>(py));
}
@ -321,7 +315,7 @@ mod bigint_conversion {
1,
$is_signed,
);
PyObject::from_owned_ptr_or_panic(py, obj)
PyObject::from_owned_ptr(py, obj)
}
}
}

View File

@ -397,11 +397,10 @@ impl<'v> PyTryFrom<'v> for PySequence {
#[cfg(test)]
mod test {
use crate::instance::AsPyRef;
use crate::object::PyObject;
use crate::types::PySequence;
use crate::AsPyPointer;
use crate::Python;
use crate::{PyTryFrom, ToPyObject};
use crate::{PyObject, PyTryFrom, ToPyObject};
fn get_object() -> PyObject {
// Convenience function for getting a single unique object

View File

@ -3,7 +3,7 @@
use crate::err::{self, PyErr, PyResult};
use crate::{
ffi, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python,
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyNativeType, PyObject, Python,
ToBorrowedObject, ToPyObject,
};
use std::cmp;
@ -185,15 +185,15 @@ where
}
}
impl<K, S> FromPy<HashSet<K, S>> for PyObject
impl<K, S> IntoPy<PyObject> for HashSet<K, S>
where
K: IntoPy<PyObject> + Eq + hash::Hash,
S: hash::BuildHasher + Default,
{
fn from_py(src: HashSet<K, S>, py: Python) -> Self {
fn into_py(self, py: Python) -> PyObject {
let set = PySet::empty(py).expect("Failed to construct empty set");
{
for val in src {
for val in self {
set.add(val.into_py(py)).expect("Failed to add to set");
}
}
@ -212,14 +212,14 @@ where
}
}
impl<K> FromPy<BTreeSet<K>> for PyObject
impl<K> IntoPy<PyObject> for BTreeSet<K>
where
K: IntoPy<PyObject> + cmp::Ord + ToPyObject,
K: IntoPy<PyObject> + cmp::Ord,
{
fn from_py(src: BTreeSet<K>, py: Python) -> Self {
fn into_py(self, py: Python) -> PyObject {
let set = PySet::empty(py).expect("Failed to construct empty set");
{
for val in src {
for val in self {
set.add(val.into_py(py)).expect("Failed to add to set");
}
}

View File

@ -2,7 +2,7 @@
use crate::types::PyBytes;
use crate::{
ffi, AsPyPointer, FromPy, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult,
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult,
PyTryFrom, Python, ToPyObject,
};
use std::borrow::Cow;
@ -112,9 +112,9 @@ impl ToPyObject for String {
}
}
impl FromPy<String> for PyObject {
fn from_py(other: String, py: Python) -> Self {
PyString::new(py, &other).into()
impl IntoPy<PyObject> for String {
fn into_py(self, py: Python) -> PyObject {
PyString::new(py, &self).into()
}
}
@ -147,9 +147,8 @@ impl<'source> FromPyObject<'source> for String {
mod test {
use super::PyString;
use crate::instance::AsPyRef;
use crate::object::PyObject;
use crate::Python;
use crate::{FromPyObject, PyTryFrom, ToPyObject};
use crate::{FromPyObject, PyObject, PyTryFrom, ToPyObject};
#[test]
fn test_non_bmp() {

View File

@ -2,8 +2,8 @@
use crate::ffi::{self, Py_ssize_t};
use crate::{
exceptions, AsPyPointer, FromPy, 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;
@ -129,12 +129,6 @@ impl<'a> IntoIterator for &'a PyTuple {
}
}
impl<'a> FromPy<&'a PyTuple> for Py<PyTuple> {
fn from_py(tuple: &'a PyTuple, _py: Python) -> Py<PyTuple> {
unsafe { Py::from_borrowed_ptr(tuple.py(), tuple.as_ptr()) }
}
}
fn wrong_tuple_length(t: &PyTuple, expected_length: usize) -> PyErr {
let msg = format!(
"Expected tuple of length {}, but got tuple of length {}.",
@ -150,7 +144,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.to_object(py).into_ptr());)+
PyObject::from_owned_ptr_or_panic(py, ptr)
PyObject::from_owned_ptr(py, ptr)
}
}
}
@ -159,7 +153,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+
PyObject::from_owned_ptr_or_panic(py, ptr)
PyObject::from_owned_ptr(py, ptr)
}
}
}
@ -169,7 +163,7 @@ macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+
unsafe {
let ptr = ffi::PyTuple_New($length);
$(ffi::PyTuple_SetItem(ptr, $n, self.$n.into_py(py).into_ptr());)+
Py::from_owned_ptr_or_panic(py, ptr)
Py::from_owned_ptr(py, ptr)
}
}
}