commit
d43a34986d
|
@ -30,6 +30,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
* `PyTypeInfo::BaseLayout` and `PyClass::BaseNativeType`. [#770](https://github.com/PyO3/pyo3/pull/770)
|
||||
* `PyDowncastImpl`. [#770](https://github.com/PyO3/pyo3/pull/770)
|
||||
* Implement `FromPyObject` and `IntoPy<PyObject>` traits for arrays (up to 32). [#778](https://github.com/PyO3/pyo3/pull/778)
|
||||
* `migration.md` and `types.md` in the guide. [#795](https://github.com/PyO3/pyo3/pull/795), #[802](https://github.com/PyO3/pyo3/pull/802)
|
||||
* `ffi::{_PyBytes_Resize, _PyDict_Next, _PyDict_Contains, _PyDict_GetDictPtr}`. #[820](https://github.com/PyO3/pyo3/pull/820)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -39,7 +41,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
* Usage of `PyObject` with `#[pyo3(get)]`. [#760](https://github.com/PyO3/pyo3/pull/760)
|
||||
* `#[pymethods]` used in conjunction with `#[cfg]`. #[769](https://github.com/PyO3/pyo3/pull/769)
|
||||
* `"*"` in a `#[pyfunction()]` argument list incorrectly accepting any number of positional arguments (use `args = "*"` when this behaviour is desired). #[792](https://github.com/PyO3/pyo3/pull/792)
|
||||
* `PyModule::dict` #[809](https://github.com/PyO3/pyo3/pull/809)
|
||||
* `PyModule::dict`. #[809](https://github.com/PyO3/pyo3/pull/809)
|
||||
* Fix the case where `DESCRIPTION` is not null-terminated. #[822](https://github.com/PyO3/pyo3/pull/822)
|
||||
|
||||
### Removed
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3"
|
||||
version = "0.9.0-alpha.1"
|
||||
version = "0.9.0"
|
||||
description = "Bindings to Python interpreter"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
readme = "README.md"
|
||||
|
@ -27,7 +27,7 @@ num-complex = { version = "0.2", optional = true }
|
|||
num-traits = "0.2.8"
|
||||
parking_lot = { version = "0.10", features = ["nightly"] }
|
||||
paste = "0.1.6"
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.9.0-alpha.1" }
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.9.0" }
|
||||
unindent = "0.1.4"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -50,7 +50,7 @@ name = "string_sum"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies.pyo3]
|
||||
version = "0.9.0-alpha.1"
|
||||
version = "0.9.0"
|
||||
features = ["extension-module"]
|
||||
```
|
||||
|
||||
|
@ -95,7 +95,7 @@ Add `pyo3` to your `Cargo.toml` like this:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
pyo3 = "0.9.0-alpha.1"
|
||||
pyo3 = "0.9.0"
|
||||
```
|
||||
|
||||
Example program displaying the value of `sys.version` and the current user name:
|
||||
|
|
|
@ -7,7 +7,6 @@ To define a custom Python class, a Rust struct needs to be annotated with the
|
|||
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass {
|
||||
num: i32,
|
||||
|
@ -15,8 +14,8 @@ struct MyClass {
|
|||
}
|
||||
```
|
||||
|
||||
The above example generates implementations for `PyTypeInfo`, `PyTypeObject`,
|
||||
and `PyClass` for `MyClass`.
|
||||
The above example generates implementations for [`PyTypeInfo`], [`PyTypeObject`],
|
||||
and [`PyClass`] for `MyClass`.
|
||||
|
||||
Specifically, the following implementation is generated:
|
||||
|
||||
|
@ -111,14 +110,14 @@ fn mymodule(_py: Python, m: &PyModule) -> PyResult<()> {
|
|||
|
||||
You sometimes need to convert your `pyclass` into a Python object and access it
|
||||
from Rust code (e.g., for testing it).
|
||||
[`PyCell`](https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html) is the primary interface for that.
|
||||
[`PyCell`] is the primary interface for that.
|
||||
|
||||
`PyCell<T: PyClass>` is always allocated in the Python heap, so Rust doesn't have ownership of it.
|
||||
In other words, Rust code can only extract a `&PyCell<T>`, not a `PyCell<T>`.
|
||||
|
||||
Thus, to mutate data behind `&PyCell` safely, PyO3 employs the
|
||||
[Interior Mutability Pattern](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html)
|
||||
like [std::cell::RefCell](https://doc.rust-lang.org/std/cell/struct.RefCell.html).
|
||||
like [`RefCell`].
|
||||
|
||||
Users who are familiar with `RefCell` can use `PyCell` just like `RefCell`.
|
||||
|
||||
|
@ -158,7 +157,7 @@ let obj = PyCell::new(py, MyClass { num: 3, debug: true }).unwrap();
|
|||
pyo3::py_run!(py, obj, "assert obj.num == 5")
|
||||
```
|
||||
|
||||
`&PyCell<T>` is bounded by the same lifetime as a `GILGuard`.
|
||||
`&PyCell<T>` is bounded by the same lifetime as a [`GILGuard`].
|
||||
To make the object longer lived (for example, to store it in a struct on the
|
||||
Rust side), you can use `Py<T>`, which stores an object longer than the GIL
|
||||
lifetime, and therefore needs a `Python<'_>` token to access.
|
||||
|
@ -190,7 +189,7 @@ The `#[pyclass]` macro accepts the following parameters:
|
|||
The performance improvement applies to types that are often created and deleted in a row,
|
||||
so that they can benefit from a freelist. `XXX` is a number of items for the free list.
|
||||
* `gc` - Classes with the `gc` parameter participate in Python garbage collection.
|
||||
If a custom class contains references to other Python objects that can be collected, the `PyGCProtocol` trait has to be implemented.
|
||||
If a custom class contains references to other Python objects that can be collected, the [`PyGCProtocol`] trait has to be implemented.
|
||||
* `weakref` - Adds support for Python weak references.
|
||||
* `extends=BaseType` - Use a custom base class. The base `BaseType` must implement `PyTypeInfo`.
|
||||
* `subclass` - Allows Python classes to inherit from this class.
|
||||
|
@ -234,10 +233,10 @@ For constructors that may fail, you should wrap the return type in a PyResult as
|
|||
Consult the table below to determine which type your constructor should return:
|
||||
|
||||
| | **Cannot fail** | **May fail** |
|
||||
|-----------------------------|-------------------------|-----------------------------------|
|
||||
|-----------------------------|---------------------------|-----------------------------------|
|
||||
|**No inheritance** | `T` | `PyResult<T>` |
|
||||
|**Inheritance(T Inherits U)**| `(T, U)` | `PyResult<(T, U)>` |
|
||||
|**Inheritance(General Case)**| `PyClassInitializer<T>` | `PyResult<PyClassInitializer<T>>` |
|
||||
|**Inheritance(General Case)**| [`PyClassInitializer<T>`] | `PyResult<PyClassInitializer<T>>` |
|
||||
|
||||
## Inheritance
|
||||
|
||||
|
@ -249,8 +248,8 @@ baseclass of `T`.
|
|||
But for more deeply nested inheritance, you have to return `PyClassInitializer<T>`
|
||||
explicitly.
|
||||
|
||||
To get a parent class from a child, use `PyRef<T>` instead of `&self` for methods,
|
||||
or `PyRefMut<T>` instead of `&mut self`.
|
||||
To get a parent class from a child, use [`PyRef`] instead of `&self` for methods,
|
||||
or [`PyRefMut`] instead of `&mut self`.
|
||||
Then you can access a parent class by `self_.as_ref()` as `&Self::BaseClass`,
|
||||
or by `self_.into_super()` as `PyRef<Self::BaseClass>`.
|
||||
|
||||
|
@ -694,7 +693,7 @@ each protocol implementation block has to be annotated with the `#[pyproto]` att
|
|||
|
||||
### Basic object customization
|
||||
|
||||
The [`PyObjectProtocol`](https://docs.rs/pyo3/latest/pyo3/class/basic/trait.PyObjectProtocol.html) trait provides several basic customizations.
|
||||
The [`PyObjectProtocol`] trait provides several basic customizations.
|
||||
|
||||
#### Attribute access
|
||||
|
||||
|
@ -748,7 +747,7 @@ Each method corresponds to Python's `self.attr`, `self.attr = value` and `del se
|
|||
If your type owns references to other Python objects, you will need to
|
||||
integrate with Python's garbage collector so that the GC is aware of
|
||||
those references.
|
||||
To do this, implement the [`PyGCProtocol`](https://docs.rs/pyo3/latest/pyo3/class/gc/trait.PyGCProtocol.html) trait for your struct.
|
||||
To do this, implement the [`PyGCProtocol`] trait for your struct.
|
||||
It includes two methods `__traverse__` and `__clear__`.
|
||||
These correspond to the slots `tp_traverse` and `tp_clear` in the Python C API.
|
||||
`__traverse__` must call `visit.call()` for each reference to another Python object.
|
||||
|
@ -842,3 +841,17 @@ pyclass dependent on whether there is an impl block, we'd need to implement the
|
|||
only possible with the specialization feature, which can't be used on stable.
|
||||
|
||||
To escape this we use [inventory](https://github.com/dtolnay/inventory), which allows us to collect `impl`s from arbitrary source code by exploiting some binary trick. See [inventory: how it works](https://github.com/dtolnay/inventory#how-it-works) and `pyo3_derive_backend::py_class::impl_inventory` for more details.
|
||||
|
||||
[`GILGuard`]: https://docs.rs/pyo3/latest/pyo3/struct.GILGuard.html
|
||||
[`PyGCProtocol`]: https://docs.rs/pyo3/latest/pyo3/class/gc/trait.PyGCProtocol.html
|
||||
[`PyObjectProtocol`]: https://docs.rs/pyo3/latest/pyo3/class/basic/trait.PyObjectProtocol.html
|
||||
[`PyTypeInfo`]: https://docs.rs/pyo3/latest/pyo3/type_object/trait.PyTypeInfo.html
|
||||
[`PyTypeObject`]: https://docs.rs/pyo3/latest/pyo3/type_object/trait.PyTypeObject.html
|
||||
|
||||
[`PyCell`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html
|
||||
[`PyClass`]: https://pyo3.rs/master/doc/pyo3/pyclass/trait.PyClass.html
|
||||
[`PyRef`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRef.html
|
||||
[`PyRefMut`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRefMut.html
|
||||
[`PyClassInitializer<T>`]: https://pyo3.rs/master/doc/pyo3/pyclass_init/struct.PyClassInitializer.html
|
||||
|
||||
[`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
|
||||
|
|
|
@ -14,27 +14,27 @@ let v: Vec<i32> = obj.extract()?;
|
|||
|
||||
This method is available for many Python object types, and can produce a wide
|
||||
variety of Rust types, which you can check out in the implementor list of
|
||||
[`FromPyObject`][FromPyObject].
|
||||
[`FromPyObject`].
|
||||
|
||||
`FromPyObject` is also implemented for your own Rust types wrapped as Python
|
||||
[`FromPyObject`] is also implemented for your own Rust types wrapped as Python
|
||||
objects (see [the chapter about classes](class.md)). There, in order to both be
|
||||
able to operate on mutable references *and* satisfy Rust's rules of non-aliasing
|
||||
mutable references, you have to extract the PyO3 reference wrappers `PyRef<T>`
|
||||
and `PyRefMut<T>`. They work like the reference wrappers of
|
||||
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.
|
||||
|
||||
|
||||
## The `ToPyObject` trait
|
||||
|
||||
[`ToPyObject`] is a conversion trait that allows various objects to be
|
||||
converted into [`PyObject`][PyObject]. `IntoPy<PyObject>` serves the
|
||||
converted into [`PyObject`]. `IntoPy<PyObject>` serves the
|
||||
same purpose, except that it consumes `self`.
|
||||
|
||||
|
||||
## `*args` and `**kwargs` for Python object calls
|
||||
|
||||
There are several ways how to pass positional and keyword arguments to a Python object call.
|
||||
The [`ObjectProtocol`][ObjectProtocol] trait provides two methods:
|
||||
The [`ObjectProtocol`] trait provides two methods:
|
||||
|
||||
* `call` - call any callable Python object.
|
||||
* `call_method` - call a specific method on the object, shorthand for `get_attr` then `call`.
|
||||
|
@ -77,7 +77,7 @@ fn main() {
|
|||
```
|
||||
|
||||
`kwargs` can be `None` or `Some(&PyDict)`. You can use the
|
||||
[`IntoPyDict`][IntoPyDict] trait to convert other dict-like containers,
|
||||
[`IntoPyDict`] trait to convert other dict-like containers,
|
||||
e.g. `HashMap` or `BTreeMap`, as well as tuples with up to 10 elements and
|
||||
`Vec`s where each element is a two-element tuple.
|
||||
|
||||
|
@ -122,14 +122,23 @@ 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<T>` 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.
|
||||
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<T> for free.
|
||||
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`.
|
||||
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/trait.IntoPy.html
|
||||
[`FromPy`]: https://docs.rs/pyo3/latest/pyo3/trait.FromPy.html
|
||||
[`FromPyObject`]: https://docs.rs/pyo3/latest/pyo3/types/trait.FromPyObject.html
|
||||
[`ToPyObject`]: https://docs.rs/pyo3/latest/pyo3/trait.ToPyObject.html
|
||||
[PyObject]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
|
||||
[PyTuple]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyTuple.html
|
||||
[ObjectProtocol]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html
|
||||
[IntoPyDict]: https://docs.rs/pyo3/latest/pyo3/types/trait.IntoPyDict.html
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject.html
|
||||
[`PyTuple`]: https://docs.rs/pyo3/latest/pyo3/types/struct.PyTuple.html
|
||||
[`ObjectProtocol`]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html
|
||||
[`IntoPyDict`]: https://docs.rs/pyo3/latest/pyo3/types/trait.IntoPyDict.html
|
||||
|
||||
[`PyRef`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRef.html
|
||||
[`PyRefMut`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRefMut.html
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Defining a new exception
|
||||
|
||||
You can use the `create_exception!` macro to define a new exception type:
|
||||
You can use the [`create_exception!`] macro to define a new exception type:
|
||||
|
||||
```rust
|
||||
use pyo3::create_exception;
|
||||
|
@ -35,7 +35,7 @@ fn main() {
|
|||
|
||||
## Raising an exception
|
||||
|
||||
To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`](https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html), then call the [`PyErr::restore()`](https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state.
|
||||
To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`], then call the [`PyErr::restore`](https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state.
|
||||
|
||||
```rust
|
||||
use pyo3::{Python, PyErr};
|
||||
|
@ -53,8 +53,7 @@ fn main() {
|
|||
From `pyfunction`s and `pyclass` methods, returning an `Err(PyErr)` is enough;
|
||||
PyO3 will handle restoring the exception on the Python interpreter side.
|
||||
|
||||
If you already have a Python exception instance, you can simply call
|
||||
[`PyErr::from_instance()`](https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html#method.from_instance).
|
||||
If you already have a Python exception instance, you can simply call [`PyErr::from_instance`].
|
||||
|
||||
```rust,ignore
|
||||
PyErr::from_instance(py, err).restore(py);
|
||||
|
@ -62,7 +61,7 @@ PyErr::from_instance(py, err).restore(py);
|
|||
|
||||
If a Rust type exists for the exception, then it is possible to use the `py_err` method.
|
||||
For example, each standard exception defined in the `pyo3::exceptions` module
|
||||
has a corresponding Rust type, exceptions defined by `create_exception!` and `import_exception!` macro
|
||||
has a corresponding Rust type, exceptions defined by [`create_exception!`] and [`import_exception!`] macro
|
||||
have Rust types as well.
|
||||
|
||||
```rust
|
||||
|
@ -81,7 +80,7 @@ fn my_func(arg: PyObject) -> PyResult<()> {
|
|||
## Checking exception types
|
||||
|
||||
Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#isinstance) method to check an object's type,
|
||||
in PyO3 there is a [`Python::is_instance()`](https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.is_instance) method which does the same thing.
|
||||
in PyO3 there is a [`Python::is_instance`] method which does the same thing.
|
||||
|
||||
```rust
|
||||
use pyo3::Python;
|
||||
|
@ -96,8 +95,8 @@ fn main() {
|
|||
assert!(py.is_instance::<PyList, _>(list.as_ref()).unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
[`Python::is_instance()`](https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.is_instance) calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance) method to do the actual work.
|
||||
[`Python::is_instance`] calls the underlying [`PyType::is_instance`](https://docs.rs/pyo3/latest/pyo3/types/struct.PyType.html#method.is_instance)
|
||||
method to do the actual work.
|
||||
|
||||
To check the type of an exception, you can simply do:
|
||||
|
||||
|
@ -114,13 +113,13 @@ err.is_instance::<exceptions::TypeError>(py);
|
|||
|
||||
## Handling Rust errors
|
||||
|
||||
The vast majority of operations in this library will return [`PyResult<T>`](https://docs.rs/pyo3/latest/pyo3/prelude/type.PyResult.html).
|
||||
This is an alias for the type `Result<T, PyErr>`.
|
||||
The vast majority of operations in this library will return [`PyResult<T>`](https://docs.rs/pyo3/latest/pyo3/prelude/type.PyResult.html),
|
||||
which is an alias for the type `Result<T, PyErr>`.
|
||||
|
||||
A [`PyErr`](https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html) represents a Python exception.
|
||||
A [`PyErr`] represents a Python exception.
|
||||
Errors within the PyO3 library are also exposed as Python exceptions.
|
||||
|
||||
The PyO3 library handles Python exceptions in two stages. During the first stage, a `PyErr` instance is
|
||||
The PyO3 library handles Python exceptions in two stages. During the first stage, a [`PyErr`] instance is
|
||||
created. At this stage, holding Python's GIL is not required. During the second stage, an actual Python
|
||||
exception instance is created and set active in the Python interpreter.
|
||||
|
||||
|
@ -151,7 +150,6 @@ until a `Python` object is available.
|
|||
# fn bind(_addr: &str) -> Result<(), CustomIOError> {
|
||||
# Err(CustomIOError)
|
||||
# }
|
||||
|
||||
impl std::convert::From<CustomIOError> for PyErr {
|
||||
fn from(err: CustomIOError) -> PyErr {
|
||||
exceptions::OSError::py_err(err.to_string())
|
||||
|
@ -208,3 +206,10 @@ fn tell(file: PyObject) -> PyResult<u64> {
|
|||
|
||||
[`pyo3::exceptions`](https://docs.rs/pyo3/latest/pyo3/exceptions/index.html)
|
||||
defines exceptions for several standard library modules.
|
||||
|
||||
[`create_exception!`]: https://docs.rs/pyo3/latest/pyo3/macro.create_exception.html
|
||||
[`import_exception!`]: https://docs.rs/pyo3/latest/pyo3/macro.import_exception.html
|
||||
|
||||
[`PyErr`]: https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html
|
||||
[`PyErr::from_instance`]: https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html#method.from_instance
|
||||
[`Python::is_instance`]: https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.is_instance
|
||||
|
|
|
@ -177,8 +177,15 @@ Currently, there are no conversions between `Fn`s in Rust and callables in Pytho
|
|||
|
||||
### Calling Python functions in Rust
|
||||
|
||||
You can use `ObjectProtocol::is_callable` to check if you have a callable object. `is_callable` will return `true` for functions (including lambdas), methods and objects with a `__call__` method. You can call the object with `ObjectProtocol::call` with the args as first parameter and the kwargs (or `None`) as second parameter. There are also `ObjectProtocol::call0` with no args and `ObjectProtocol::call1` with only positional args.
|
||||
You can use [`ObjectProtocol::is_callable`] to check if you have a callable object. `is_callable` will return `true` for functions (including lambdas), methods and objects with a `__call__` method. You can call the object with [`ObjectProtocol::call`] with the args as first parameter and the kwargs (or `None`) as second parameter. There are also [`ObjectProtocol::call0`] with no args and [`ObjectProtocol::call1`] with only positional args.
|
||||
|
||||
### Calling Rust functions in Python
|
||||
|
||||
If you have a static function, you can expose it with `#[pyfunction]` and use `wrap_pyfunction!` to get the corresponding `PyObject`. For dynamic functions, e.g. lambdas and functions that were passed as arguments, you must put them in some kind of owned container, e.g. a `Box`. (A long-term solution will be a special container similar to wasm-bindgen's `Closure`). You can then use a `#[pyclass]` struct with that container as a field as a way to pass the function over the FFI barrier. You can even make that class callable with `__call__` so it looks like a function in Python code.
|
||||
If you have a static function, you can expose it with `#[pyfunction]` and use [`wrap_pyfunction!`] to get the corresponding [`PyObject`]. For dynamic functions, e.g. lambdas and functions that were passed as arguments, you must put them in some kind of owned container, e.g. a `Box`. (A long-term solution will be a special container similar to wasm-bindgen's `Closure`). You can then use a `#[pyclass]` struct with that container as a field as a way to pass the function over the FFI barrier. You can even make that class callable with `__call__` so it looks like a function in Python code.
|
||||
|
||||
[`ObjectProtocol::is_callable`]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html#tymethod.is_callable
|
||||
[`ObjectProtocol::call`]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html#tymethod.call
|
||||
[`ObjectProtocol::call0`]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html#tymethod.call0
|
||||
[`ObjectProtocol::call1`]: https://docs.rs/pyo3/latest/pyo3/trait.ObjectProtocol.html#tymethod.call1
|
||||
[`PyObject`]: https://docs.rs/pyo3/latest/pyo3/struct.PyObject
|
||||
[`wrap_pyfunction!`]: https://docs.rs/pyo3/latest/pyo3/macro.wrap_pyfunction.html
|
||||
|
|
|
@ -44,7 +44,7 @@ name = "string_sum"
|
|||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies.pyo3]
|
||||
version = "0.9.0-alpha.1"
|
||||
version = "0.9.0"
|
||||
features = ["extension-module"]
|
||||
```
|
||||
|
||||
|
@ -90,7 +90,7 @@ use it to run Python code, add `pyo3` to your `Cargo.toml` like this:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
pyo3 = "0.9.0-alpha.1"
|
||||
pyo3 = "0.9.0"
|
||||
```
|
||||
|
||||
Example program displaying the value of `sys.version` and the current user name:
|
||||
|
|
|
@ -7,7 +7,7 @@ This guide can help you upgrade code through breaking changes from one PyO3 vers
|
|||
is now removed and our syntax for constructors has changed.
|
||||
|
||||
Before:
|
||||
```compile_fail
|
||||
```rust,compile_fail
|
||||
#[pyclass]
|
||||
struct MyClass {}
|
||||
|
||||
|
@ -21,7 +21,7 @@ impl MyClass {
|
|||
```
|
||||
|
||||
After:
|
||||
```
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
#[pyclass]
|
||||
struct MyClass {}
|
||||
|
@ -39,8 +39,7 @@ Basically you can return `Self` or `Result<Self>` directly.
|
|||
For more, see [the constructor section](https://pyo3.rs/master/class.html#constructor) of this guide.
|
||||
|
||||
### PyCell
|
||||
PyO3 0.9 introduces [`PyCell`](https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html), which is
|
||||
a [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html)-like object wrapper
|
||||
PyO3 0.9 introduces [`PyCell`], which is a [`RefCell`]-like object wrapper
|
||||
for ensuring Rust's rules regarding aliasing of references are upheld.
|
||||
For more detail, see the
|
||||
[Rust Book's section on Rust's rules of references](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#the-rules-of-references)
|
||||
|
@ -50,7 +49,7 @@ Python exceptions will automatically be raised when your functions are used in a
|
|||
rules of references.
|
||||
|
||||
Here is an example.
|
||||
```
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
#[pyclass]
|
||||
struct Names {
|
||||
|
@ -75,25 +74,26 @@ impl Names {
|
|||
# try:
|
||||
# names.merge(names)
|
||||
# assert False, 'Unreachable'
|
||||
# except Exception as e:
|
||||
# except RuntimeError as e:
|
||||
# isinstance(e, borrow_mut_err)
|
||||
# ");
|
||||
```
|
||||
`Names` has a `merge` method, which takes `&mut self` and another argument of type `&mut Self`.
|
||||
Given this `#[pyclass]`, calling `names.merge(names)` in Python raises a `PyBorrowMutError` exception,
|
||||
since it requires two mutable borrows of `names`.
|
||||
Given this `#[pyclass]`, calling `names.merge(names)` in Python raises
|
||||
a [`PyBorrowMutError`] exception, since it requires two mutable borrows of `names`.
|
||||
|
||||
However, for `#[pyproto]` and some functions, you need to manually fix the code.
|
||||
|
||||
#### Object creation
|
||||
In 0.8 object creation was done with `PyRef::new` and `PyRefMut::new`.
|
||||
In 0.9 these have both been removed.
|
||||
To upgrade code, please use `PyCell::new` instead.
|
||||
If a `PyRef` or `PyRefMut` is needed, just call `.borrow()` or `.borrow_mut()`
|
||||
To upgrade code, please use
|
||||
[`PyCell::new`](https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html#method.new) instead.
|
||||
If you need [`PyRef`] or [`PyRefMut`], just call `.borrow()` or `.borrow_mut()`
|
||||
on the newly-created `PyCell`.
|
||||
|
||||
Before:
|
||||
```compile_fail
|
||||
```rust,compile_fail
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# struct MyClass {}
|
||||
|
@ -103,7 +103,7 @@ let obj_ref = PyRef::new(py, MyClass {}).unwrap();
|
|||
```
|
||||
|
||||
After:
|
||||
```
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# #[pyclass]
|
||||
# struct MyClass {}
|
||||
|
@ -114,7 +114,7 @@ let obj_ref = obj.borrow();
|
|||
```
|
||||
|
||||
#### Object extraction
|
||||
For `PyClass` types `T`, `&T` and `&mut T` no longer have `FromPyObject` implementations.
|
||||
For `PyClass` types `T`, `&T` and `&mut T` no longer have [`FromPyObject`] implementations.
|
||||
Instead you should extract `PyRef<T>` or `PyRefMut<T>`, respectively.
|
||||
If `T` implements `Clone`, you can extract `T` itself.
|
||||
In addition, you can also extract `&PyCell<T>`, though you rarely need it.
|
||||
|
@ -127,7 +127,7 @@ let obj_ref_mut: &mut MyClass = obj.extract().unwrap();
|
|||
```
|
||||
|
||||
After:
|
||||
```
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::types::IntoPyDict;
|
||||
# #[pyclass] #[derive(Clone)] struct MyClass {}
|
||||
|
@ -149,12 +149,13 @@ let obj_ref_mut: PyRefMut<MyClass> = obj.extract().unwrap();
|
|||
|
||||
|
||||
#### `#[pyproto]`
|
||||
Most of the arguments to methods in `#[pyproto]` impls require a [`FromPyObject`] implementation.
|
||||
Most of the arguments to methods in `#[pyproto]` impls require a
|
||||
[`FromPyObject`] implementation.
|
||||
So if your protocol methods take `&T` or `&mut T` (where `T: PyClass`),
|
||||
please use `PyRef` or `PyRefMut` instead.
|
||||
please use [`PyRef`] or [`PyRefMut`] instead.
|
||||
|
||||
Before:
|
||||
```compile_fail
|
||||
```rust,compile_fail
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::class::PySequenceProtocol;
|
||||
#[pyclass]
|
||||
|
@ -172,7 +173,7 @@ impl PySequenceProtocol for ByteSequence {
|
|||
```
|
||||
|
||||
After:
|
||||
```
|
||||
```rust
|
||||
# use pyo3::prelude::*;
|
||||
# use pyo3::class::PySequenceProtocol;
|
||||
#[pyclass]
|
||||
|
@ -188,3 +189,12 @@ impl PySequenceProtocol for ByteSequence {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
[`FromPyObject`]: https://docs.rs/pyo3/latest/pyo3/conversion/trait.FromPyObject.html
|
||||
|
||||
[`PyCell`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyCell.html
|
||||
[`PyBorrowMutError`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyBorrowMutError.html
|
||||
[`PyRef`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRef.html
|
||||
[`PyRefMut`]: https://pyo3.rs/master/doc/pyo3/pycell/struct.PyRefMut.html
|
||||
|
||||
[`RefCell`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html
|
||||
|
|
|
@ -6,8 +6,7 @@ hold the GIL by default when called from Python, in order to allow manipulation
|
|||
of Python objects, you can release the GIL when executing Rust-only code to
|
||||
achieve true parallelism.
|
||||
|
||||
The [`Python::allow_threads`](https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.allow_threads)
|
||||
method temporarily releases the GIL, thus allowing other Python threads to run.
|
||||
The [`Python::allow_threads`] method temporarily releases the GIL, thus allowing other Python threads to run.
|
||||
|
||||
```rust,ignore
|
||||
impl Python {
|
||||
|
@ -26,7 +25,8 @@ fn wc_parallel(lines: &str, search: &str) -> i32 {
|
|||
}
|
||||
```
|
||||
|
||||
Then in the Python bridge, we have a function `search` exposed to the Python runtime which calls `wc_parallel` inside a closure passed to `Python::allow_threads` to enable true parallelism:
|
||||
Then in the Python bridge, we have a function `search` exposed to the Python runtime which calls
|
||||
`wc_parallel` inside a closure passed to [`Python::allow_threads`] to enable true parallelism:
|
||||
|
||||
```rust,ignore
|
||||
#[pymodule]
|
||||
|
@ -61,3 +61,6 @@ then we can run `pytest tests` to benchmark them.
|
|||
On MacBook Pro (Retina, 15-inch, Mid 2015) the benchmark gives:
|
||||
|
||||
![Benchmark Result](https://user-images.githubusercontent.com/1556054/28604608-81bd6d22-71fe-11e7-8a2c-c3cf3bd0f622.png)
|
||||
|
||||
|
||||
[`Python::allow_threads`]: https://docs.rs/pyo3/latest/pyo3/struct.Python.html#method.allow_threads
|
||||
|
|
|
@ -27,15 +27,13 @@ fn main() -> Result<(), ()> {
|
|||
|
||||
## Want to run statements? Then use `run`.
|
||||
|
||||
[`Python::run`](https://pyo3.rs/master/doc/pyo3/struct.Python.html#method.run)
|
||||
is a method to execute one or more
|
||||
[`Python::run`] is a method to execute one or more
|
||||
[Python statements](https://docs.python.org/3.7/reference/simple_stmts.html).
|
||||
This method returns nothing (like any Python statement), but you can get
|
||||
access to manipulated objects via the `locals` dict.
|
||||
|
||||
You can also use the [`py_run!`](https://pyo3.rs/master/doc/pyo3/macro.py_run.html)
|
||||
macro, which is a shorthand for `Python::run`.
|
||||
Since `py_run!` panics on exceptions, we recommend you use this macro only for
|
||||
You can also use the [`py_run!`] macro, which is a shorthand for [`Python::run`].
|
||||
Since [`py_run!`] panics on exceptions, we recommend you use this macro only for
|
||||
quickly testing your Python extensions.
|
||||
|
||||
```rust
|
||||
|
@ -103,3 +101,6 @@ let lrelu_result: f64 = activators
|
|||
assert_eq!(lrelu_result, -0.2);
|
||||
# Ok(()) }
|
||||
```
|
||||
|
||||
[`Python::run`]: https://pyo3.rs/master/doc/pyo3/struct.Python.html#method.run
|
||||
[`py_run!`]: https://pyo3.rs/master/doc/pyo3/macro.py_run.html
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-derive-backend"
|
||||
version = "0.9.0-alpha.1"
|
||||
version = "0.9.0"
|
||||
description = "Code generation for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3cls"
|
||||
version = "0.9.0-alpha.1"
|
||||
version = "0.9.0"
|
||||
description = "Proc macros for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
@ -16,4 +16,4 @@ proc-macro = true
|
|||
[dependencies]
|
||||
quote = "1"
|
||||
syn = { version = "1", features = ["full", "extra-traits"] }
|
||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.9.0-alpha.1" }
|
||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.9.0" }
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
//! crate-type = ["cdylib"]
|
||||
//!
|
||||
//! [dependencies.pyo3]
|
||||
//! version = "0.9.0-alpha.1"
|
||||
//! version = "0.9.0"
|
||||
//! features = ["extension-module"]
|
||||
//! ```
|
||||
//!
|
||||
|
@ -109,7 +109,7 @@
|
|||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! pyo3 = "0.9.0-alpha.1"
|
||||
//! pyo3 = "0.9.0"
|
||||
//! ```
|
||||
//!
|
||||
//! Example program displaying the value of `sys.version`:
|
||||
|
|
|
@ -662,6 +662,8 @@ impl BorrowFlag {
|
|||
}
|
||||
|
||||
/// An error returned by [`PyCell::try_borrow`](struct.PyCell.html#method.try_borrow).
|
||||
///
|
||||
/// In Python, you can catch this error by `except RuntimeError`.
|
||||
pub struct PyBorrowError {
|
||||
_private: (),
|
||||
}
|
||||
|
@ -679,6 +681,8 @@ impl fmt::Display for PyBorrowError {
|
|||
}
|
||||
|
||||
/// An error returned by [`PyCell::try_borrow_mut`](struct.PyCell.html#method.try_borrow_mut).
|
||||
///
|
||||
/// In Python, you can catch this error by `except RuntimeError`.
|
||||
pub struct PyBorrowMutError {
|
||||
_private: (),
|
||||
}
|
||||
|
@ -695,5 +699,5 @@ impl fmt::Display for PyBorrowMutError {
|
|||
}
|
||||
}
|
||||
|
||||
pyo3_exception!(PyBorrowError, crate::exceptions::Exception);
|
||||
pyo3_exception!(PyBorrowMutError, crate::exceptions::Exception);
|
||||
pyo3_exception!(PyBorrowError, crate::exceptions::RuntimeError);
|
||||
pyo3_exception!(PyBorrowMutError, crate::exceptions::RuntimeError);
|
||||
|
|
Loading…
Reference in New Issue