Merge pull request #1063 from davidhewitt/remove-pyobject
Make `PyObject` a type alias of `Py<PyAny>` (& remove `FromPy`)
This commit is contained in:
commit
bcb90775b4
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())),
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
16
src/err.rs
16
src/err.rs
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
365
src/instance.rs
365
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,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
347
src/object.rs
347
src/object.rs
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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")]
|
||||
|
|
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()) }
|
||||
}
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue