Fix various typos/omissions in guide.
This commit is contained in:
parent
5f7d67615c
commit
c91ed70bbc
|
@ -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.
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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**
|
||||
|
||||
|
|
Loading…
Reference in New Issue