Skip to content

Commit

Permalink
Merge pull request #812 from PyO3/release-0.9
Browse files Browse the repository at this point in the history
Bump version to 0.9.0
  • Loading branch information
kngwyu committed Mar 19, 2020
2 parents 25b594c + 89e5a65 commit d43a349
Show file tree
Hide file tree
Showing 15 changed files with 140 additions and 85 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

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

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
```

Expand Down Expand Up @@ -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:
Expand Down
45 changes: 29 additions & 16 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ To define a custom Python class, a Rust struct needs to be annotated with the

```rust
# use pyo3::prelude::*;

#[pyclass]
struct MyClass {
num: i32,
debug: bool,
}
```

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:

Expand Down Expand Up @@ -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`.

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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>`.

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
37 changes: 23 additions & 14 deletions guide/src/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
31 changes: 18 additions & 13 deletions guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand All @@ -53,16 +53,15 @@ 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);
```

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
Expand All @@ -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;
Expand All @@ -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:

Expand All @@ -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.

Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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

0 comments on commit d43a349

Please sign in to comment.