Merge pull request #812 from PyO3/release-0.9

Bump version to 0.9.0
This commit is contained in:
Yuji Kanagawa 2020-03-19 15:10:45 +09:00 committed by GitHub
commit d43a34986d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 140 additions and 85 deletions

View File

@ -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

View File

@ -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]

View File

@ -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:

View File

@ -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.
@ -233,11 +232,11 @@ Generally, `#[new]` method have to return `T: Into<PyClassInitializer<Self>>` or
For constructors that may fail, you should wrap the return type in a PyResult as well.
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>>` |
| | **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
@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"]

View File

@ -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" }

View File

@ -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`:

View File

@ -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);