Fix various typos/omissions in guide.

This commit is contained in:
Georg Brandl 2022-11-20 13:47:29 +01:00
parent 5f7d67615c
commit c91ed70bbc
6 changed files with 35 additions and 32 deletions

View File

@ -2,7 +2,7 @@
PyO3 exposes a group of attributes powered by Rust's proc macro system for defining Python classes as Rust structs.
The main attribute is `#[pyclass]`, which is placed upon a Rust `struct` or a fieldless `enum` (a.k.a. C-like enum) to generate a Python type for it. They will usually also have *one* `#[pymethods]`-annotated `impl` block for the struct, which is used to define Python methods and constants for the generated Python type. (If the [`multiple-pymethods`] feature is enabled each `#[pyclass]` is allowed to have multiple `#[pymethods]` blocks.) `#[pymethods]` may also have implementations for Python magic methods such as `__str__`.
The main attribute is `#[pyclass]`, which is placed upon a Rust `struct` or a fieldless `enum` (a.k.a. C-like enum) to generate a Python type for it. They will usually also have *one* `#[pymethods]`-annotated `impl` block for the struct, which is used to define Python methods and constants for the generated Python type. (If the [`multiple-pymethods`] feature is enabled, each `#[pyclass]` is allowed to have multiple `#[pymethods]` blocks.) `#[pymethods]` may also have implementations for Python magic methods such as `__str__`.
This chapter will discuss the functionality and configuration these attributes offer. Below is a list of links to the relevant section of this chapter for each:
@ -68,7 +68,7 @@ When you need to share ownership of data between Python and Rust, instead of usi
A Rust `struct Foo<T>` with a generic parameter `T` generates new compiled implementations each time it is used with a different concrete type for `T`. These new implementations are generated by the compiler at each usage site. This is incompatible with wrapping `Foo` in Python, where there needs to be a single compiled implementation of `Foo` which is integrated with the Python interpreter.
#### Must be send
#### Must be Send
Because Python objects are freely shared between threads by the Python interpreter, there is no guarantee which thread will eventually drop the object. Therefore all types annotated with `#[pyclass]` must implement `Send` (unless annotated with [`#[pyclass(unsendable)]`](#customizing-the-class)).
@ -123,7 +123,7 @@ For arguments, see the [`Method arguments`](#method-arguments) section below.
## Adding the class to a module
The next step is to create the module initializer and add our class to it
The next step is to create the module initializer and add our class to it:
```rust
# use pyo3::prelude::*;
@ -219,7 +219,7 @@ These parameters are covered in various sections of this guide.
### Return type
Generally, `#[new]` method have to return `T: Into<PyClassInitializer<Self>>` or
Generally, `#[new]` methods have to return `T: Into<PyClassInitializer<Self>>` or
`PyResult<T> where T: Into<PyClassInitializer<Self>>`.
For constructors that may fail, you should wrap the return type in a PyResult as well.

View File

@ -88,7 +88,8 @@ Traceback (most recent call last):
ValueError: invalid digit found in string
```
As a more complete example, the following snippet defines a Rust error named `CustomIOError`. It then defines a `From<CustomIOError> for PyErr`, which returns a `PyErr` representing Python's `OSError`. Finally, it
As a more complete example, the following snippet defines a Rust error named `CustomIOError`. It then defines a `From<CustomIOError> for PyErr`, which returns a `PyErr` representing Python's `OSError`.
Therefore, it can use this error in the result of a `#[pyfunction]` directly, relying on the conversion if it has to be propagated into a Python exception.
```rust
use pyo3::exceptions::PyOSError;
@ -125,6 +126,7 @@ fn bind(addr: String) -> Result<Connection, CustomIOError> {
#[pyfunction]
fn connect(s: String) -> Result<(), CustomIOError> {
bind(s)?;
// etc.
Ok(())
}

View File

@ -94,7 +94,7 @@ num=44
num=-1
```
> Note: for keywords like `struct`, to use it as a function argument, use "raw ident" syntax `r#struct` in both the signature and the function definition:
> Note: to use keywords like `struct` as a function argument, use "raw identifier" syntax `r#struct` in both the signature and the function definition:
>
> ```rust
> # #![allow(dead_code)]

View File

@ -1,30 +1,29 @@
# Installation
To get started using PyO3 you will need three things: a rust toolchain, a python environment, and a way to build. We'll cover each of these below.
To get started using PyO3 you will need three things: a Rust toolchain, a Python environment, and a way to build. We'll cover each of these below.
## Rust
First, make sure you have rust installed on your system. If you haven't already done so you can do so by following the instructions [here](https://www.rust-lang.org/tools/install). PyO3 runs on both the `stable` and `nightly` versions so you can choose whichever one fits you best. The minimum required rust version is Rust 1.48.
First, make sure you have Rust installed on your system. If you haven't already done so, try following the instructions [here](https://www.rust-lang.org/tools/install). PyO3 runs on both the `stable` and `nightly` versions so you can choose whichever one fits you best. The minimum required Rust version is 1.48.
if you can run `rustc --version` and the version is high enough you're good to go!
If you can run `rustc --version` and the version is new enough you're good to go!
## Python
To use PyO3 you need at least Python 3.7. While you can simply use the default Python version on your system, it is recommended to use a virtual environment.
To use PyO3, you need at least Python 3.7. While you can simply use the default Python interpreter on your system, it is recommended to use a virtual environment.
## Virtualenvs
While you can use any virtualenv manager you like, we recommend the use of `pyenv` especially if you want to develop or test for multiple different python versions, so that is what the examples in this book will use. The installation instructions for `pyenv` can be found [here](https://github.com/pyenv/pyenv#getting-pyenv).
While you can use any virtualenv manager you like, we recommend the use of `pyenv` in particular if you want to develop or test for multiple different Python versions, so that is what the examples in this book will use. The installation instructions for `pyenv` can be found [here](https://github.com/pyenv/pyenv#getting-pyenv).
Note that when using `pyenv` you should also set the following environment variable
Note that when using `pyenv`, you should also set the following environment variable:
```bash
PYTHON_CONFIGURE_OPTS="--enable-shared"
```
### Building
There are a number of build and python package management systems such as [`setuptools-rust`](https://github.com/PyO3/setuptools-rust) or [manually](https://pyo3.rs/latest/building_and_distribution.html#manual-builds) we recommend the use of `maturin` which you can install [here](https://maturin.rs/installation.html). It is developed to work with PyO3 and is the most "batteries included" experience. `maturin` is just a python package so you can add it in any way that you install python packages.
There are a number of build and Python package management systems such as [`setuptools-rust`](https://github.com/PyO3/setuptools-rust) or [manually](https://pyo3.rs/latest/building_and_distribution.html#manual-builds). We recommend the use of `maturin`, which you can install [here](https://maturin.rs/installation.html). It is developed to work with PyO3 and provides the most "batteries included" experience. `maturin` is just a Python package, so you can add it in the same you already install Python packages.
System Python:
```bash
@ -47,11 +46,11 @@ poetry:
poetry add -D maturin
```
after installation, you can run `maturin --version` to check that you have correctly installed it.
After installation, you can run `maturin --version` to check that you have correctly installed it.
# Starting a new project
Firstly you should create the folder and virtual environment that are going to contain your new project. Here we will use the recommended `pyenv`:
First you should create the folder and virtual environment that are going to contain your new project. Here we will use the recommended `pyenv`:
```bash
mkdir pyo3-example
@ -59,19 +58,20 @@ cd pyo3-example
pyenv virtualenv pyo3
pyenv local pyo3
```
after this, you should install your build manager. In this example, we will use `maturin`. After you've activated your virtualenv add `maturin` to it:
After this, you should install your build manager. In this example, we will use `maturin`. After you've activated your virtualenv, add `maturin` to it:
```bash
pip install maturin
```
After this, you can initialise the new project
Now you can initialise the new project:
```bash
maturin init
```
If `maturin` is already installed you can create a new project using that directly as well:
If `maturin` is already installed, you can create a new project using that directly as well:
```bash
maturin new -b pyo3 pyo3-example
@ -82,16 +82,16 @@ pyenv local pyo3
# Adding to an existing project
Sadly currently `maturin` cannot be run in existing projects, so if you want to use python in an existing project you basically have two options:
Sadly, `maturin` cannot currently be run in existing projects, so if you want to use Python in an existing project you basically have two options:
1. create a new project as above and move your existing code into that project
2. Manually edit your project configuration as necessary.
1. Create a new project as above and move your existing code into that project
2. Manually edit your project configuration as necessary
If you are opting for the second option, here are the things you need to pay attention to:
If you opt for the second option, here are the things you need to pay attention to:
## Cargo.toml
Make sure that the rust you want to be able to access from Python is compiled into a library. You can have a binary output as well, but the code you want to access from python has to be in the library. Also, make sure that the crate type is `cdylib` and add PyO3 as a dependency as so:
Make sure that the Rust crate you want to be able to access from Python is compiled into a library. You can have a binary output as well, but the code you want to access from Python has to be in the library part. Also, make sure that the crate type is `cdylib` and add PyO3 as a dependency as so:
```toml
@ -138,7 +138,7 @@ classifiers = [
## Running code
After this you can setup rust code to be available in python as below; for example, you can place this code in `src/lib.rs`:
After this you can setup Rust code to be available in Python as below; for example, you can place this code in `src/lib.rs`:
```rust
use pyo3::prelude::*;
@ -159,7 +159,7 @@ fn pyo3_example(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
}
```
After this you can run `maturin develop` to prepare the python package after which you can use it like so:
Now you can run `maturin develop` to prepare the Python package, after which you can use it like so:
```bash
$ maturin develop
@ -170,4 +170,4 @@ $ python
'25'
```
For more instructions on how to use python code from rust see the [Python from Rust](python_from_rust.md) page.
For more instructions on how to use Python code from Rust, see the [Python from Rust](python_from_rust.md) page.

View File

@ -122,11 +122,12 @@ for more information on safety.
## GIL-independent memory
Sometimes we need a reference to memory on Python's heap that can outlive the
GIL. Python's `Py<PyAny>` is analogous to `Rc<T>`, but for variables whose
GIL. Python's `Py<PyAny>` is analogous to `Arc<T>`, but for variables whose
memory is allocated on Python's heap. Cloning a `Py<PyAny>` increases its
internal reference count just like cloning `Rc<T>`. The smart pointer can
outlive the GIL from which it was created. It isn't magic, though. We need to
reacquire the GIL to access the memory pointed to by the `Py<PyAny>`.
internal reference count just like cloning `Arc<T>`. The smart pointer can
outlive the "GIL is held" period in which it was created. It isn't magic,
though. We need to reacquire the GIL to access the memory pointed to by the
`Py<PyAny>`.
What happens to the memory when the last `Py<PyAny>` is dropped and its
reference count reaches zero? It depends whether or not we are holding the GIL.

View File

@ -4,7 +4,7 @@ PyO3 began as fork of [rust-cpython](https://github.com/dgrunwald/rust-cpython)
## Macros
While rust-cpython has a `macro_rules!` based dsl for declaring modules and classes, PyO3 uses proc macros. PyO3 also doesn't change your struct and functions so you can still use them as normal Rust functions.
While rust-cpython has a `macro_rules!` based DSL for declaring modules and classes, PyO3 uses proc macros. PyO3 also doesn't change your struct and functions so you can still use them as normal Rust functions.
**rust-cpython**