Rust bindings for Python, including tools for creating native Python extension modules. Running and interacting with Python code from a Rust binary is also supported.
You can use PyO3 to write a native Python module in Rust, or to embed Python in a Rust binary. The following sections explain each of these in turn.
Using Rust from Python
PyO3 can be used to generate a native Python module. The easiest way to try this out for the first time is to use maturin. maturin is a tool for building and publishing Rust-based Python packages with minimal configuration. The following steps install maturin, use it to generate and build a new Python package, and then launch Python to import and execute a function from the package.
First, follow the commands below to create a new directory containing a new Python virtualenv, and install maturin into the virtualenv using Python's package manager, pip:
# (replace string_sum with the desired package name)
$ mkdir string_sum
$ cd string_sum
$ python -m venv .env
$ source .env/bin/activate
$ pip install maturin
Still inside this string_sum directory, now run maturin init. This will generate the new package source. When given the choice of bindings to use, select pyo3 bindings:
$ maturin init
✔ 🤷 What kind of bindings to use? · pyo3
✨ Done! New project created string_sum
The most important files generated by this command are Cargo.toml and lib.rs, which will look roughly like the following:
Cargo.toml
[package]
name = "string_sum"version = "0.1.0"edition = "2018"
[lib]
# The name of the native library. This is the name which will be used in Python to import the# library (i.e. `import string_sum`). If you change this, you must also change the name of the# `#[pymodule]` in `src/lib.rs`.name = "string_sum"# "cdylib" is necessary to produce a shared library for Python to import from.## Downstream Rust code (including code in `bin/`, `examples/`, and `tests/`) will not be able# to `use string_sum;` unless the "rlib" or "lib" crate type is also included, e.g.:# crate-type = ["cdylib", "rlib"]crate-type = ["cdylib"]
[dependencies]
pyo3 = { version = "0.18.2", features = ["extension-module"] }
src/lib.rs
use pyo3::prelude::*;/// Formats the sum of two numbers as string.#[pyfunction]fnsum_as_string(a:usize,b:usize) -> PyResult<String>{Ok((a + b).to_string())}/// A Python module implemented in Rust. The name of this function must match/// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to/// import the module.#[pymodule]fnstring_sum(_py:Python<'_>,m:&PyModule) -> PyResult<()>{
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;Ok(())}
Finally, run maturin develop. This will build the package and install it into the Python virtualenv previously created and activated. The package is then ready to be used from python:
$ maturin develop
# lots of progress output as maturin runs the compilation...
$ python
>>> import string_sum
>>> string_sum.sum_as_string(5, 20)
'25'
To make changes to the package, just edit the Rust source code and then re-run maturin develop to recompile.
To run this all as a single copy-and-paste, use the bash script below (replace string_sum in the first command with the desired package name):
If you want to be able to run cargo test or use this project in a Cargo workspace and are running into linker issues, there are some workarounds in the FAQ.
As well as with maturin, it is possible to build using setuptools-rust or manually. Both offer more flexibility than maturin but require more configuration to get started.
Using Python from Rust
To embed Python into a Rust binary, you need to ensure that your Python installation contains a shared library. The following steps demonstrate how to ensure this (for Ubuntu), and then give some example code which runs an embedded Python interpreter.
To install the Python shared library on Ubuntu:
sudo apt install python3-dev
To install the Python shared library on RPM based distributions (e.g. Fedora, Red Hat, SuSE), install the python3-devel package.
Start a new project with cargo new and add pyo3 to the Cargo.toml like this:
[dependencies.pyo3]
version = "0.18.2"features = ["auto-initialize"]
Example program displaying the value of sys.version and the current user name:
pythonizeSerde serializer for converting Rust objects to JSON-compatible Python objects
pyo3-asyncioUtilities for working with Python's Asyncio library and async functions
rustimportDirectly import Rust files or crates from Python, without manual compilation step. Provides pyo3 integration by default and generates pyo3 binding code automatically.
Examples
autopyA simple, cross-platform GUI automation library for Python and Rust.
Contains an example of building wheels on TravisCI and appveyor using cibuildwheel
ballista-pythonA Python library that binds to Apache Arrow distributed query engine Ballista.
bed-readerRead and write the PLINK BED format, simply and efficiently.
If you don't have time to contribute yourself but still wish to support the project's future success, some of our maintainers have GitHub sponsorship pages:
PyO3/pyo3
PyO3
Rust bindings for Python, including tools for creating native Python extension modules. Running and interacting with Python code from a Rust binary is also supported.
User Guide: stable | main
API Documentation: stable | main
Usage
PyO3 supports the following software versions:
You can use PyO3 to write a native Python module in Rust, or to embed Python in a Rust binary. The following sections explain each of these in turn.
Using Rust from Python
PyO3 can be used to generate a native Python module. The easiest way to try this out for the first time is to use
maturin
.maturin
is a tool for building and publishing Rust-based Python packages with minimal configuration. The following steps installmaturin
, use it to generate and build a new Python package, and then launch Python to import and execute a function from the package.First, follow the commands below to create a new directory containing a new Python
virtualenv
, and installmaturin
into the virtualenv using Python's package manager,pip
:Still inside this
string_sum
directory, now runmaturin init
. This will generate the new package source. When given the choice of bindings to use, select pyo3 bindings:The most important files generated by this command are
Cargo.toml
andlib.rs
, which will look roughly like the following:Cargo.toml
src/lib.rs
Finally, run
maturin develop
. This will build the package and install it into the Python virtualenv previously created and activated. The package is then ready to be used frompython
:To make changes to the package, just edit the Rust source code and then re-run
maturin develop
to recompile.To run this all as a single copy-and-paste, use the bash script below (replace
string_sum
in the first command with the desired package name):If you want to be able to run
cargo test
or use this project in a Cargo workspace and are running into linker issues, there are some workarounds in the FAQ.As well as with
maturin
, it is possible to build usingsetuptools-rust
or manually. Both offer more flexibility thanmaturin
but require more configuration to get started.Using Python from Rust
To embed Python into a Rust binary, you need to ensure that your Python installation contains a shared library. The following steps demonstrate how to ensure this (for Ubuntu), and then give some example code which runs an embedded Python interpreter.
To install the Python shared library on Ubuntu:
To install the Python shared library on RPM based distributions (e.g. Fedora, Red Hat, SuSE), install the
python3-devel
package.Start a new project with
cargo new
and addpyo3
to theCargo.toml
like this:Example program displaying the value of
sys.version
and the current user name:The guide has a section with lots of examples about this topic.
Tools and libraries
built
crate as aPyDict
Examples
Articles and other media
Contributing
Everyone is welcomed to contribute to PyO3! There are many ways to support the project, such as:
Our contributing notes and architecture guide have more resources if you wish to volunteer time for PyO3 and are searching where to start.
If you don't have time to contribute yourself but still wish to support the project's future success, some of our maintainers have GitHub sponsorship pages:
License
PyO3 is licensed under the Apache-2.0 license. Python is licensed under the Python License.