29 releases

✓ Uses Rust 2018 edition

0.7.0 May 26, 2019
0.6.0 Mar 28, 2019
0.5.2 Nov 25, 2018
0.4.0 Jul 30, 2018
0.1.0 Jul 23, 2017

#2 in FFI

Download history 531/week @ 2019-02-10 1015/week @ 2019-02-17 1181/week @ 2019-02-24 1679/week @ 2019-03-03 1425/week @ 2019-03-10 1156/week @ 2019-03-17 1629/week @ 2019-03-24 1187/week @ 2019-03-31 1701/week @ 2019-04-07 956/week @ 2019-04-14 1793/week @ 2019-04-21 1944/week @ 2019-04-28 1835/week @ 2019-05-05 1831/week @ 2019-05-12 3825/week @ 2019-05-19

9,178 downloads per month
Used in 22 crates


17K SLoC


Build Status Build Status codecov crates.io Join the dev chat

Rust bindings for Python. This includes running and interacting with Python code from a Rust binary, as well as writing native Python modules.

A comparison with rust-cpython can be found in the guide.


PyO3 supports Python 3.5 and up. The minimum required Rust version is 1.34.0-nightly 2019-02-06.

PyPy is also supported (via cpyext) for Python 3.5 only, targeted PyPy version is 7.0.0. Please refer to the guide for installation instruction against PyPy.

You can either write a native Python module in Rust, or use Python from a Rust binary.

However, on some OSs, you need some additional packages. E.g. if you are on Ubuntu 18.04, please run

sudo apt install python3-dev python-dev

Using Rust from Python

PyO3 can be used to generate a native Python module.


name = "string-sum"
version = "0.1.0"
edition = "2018"

name = "string_sum"
crate-type = ["cdylib"]

version = "0.7.0"
features = ["extension-module"]


use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

/// Formats the sum of two numbers as string
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
    Ok((a + b).to_string())

/// This module is a python module implemented in Rust.
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {


On Windows and Linux, you can build normally with cargo build --release. On macOS, you need to set additional linker arguments. One option is to compile with cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup, the other is to create a .cargo/config with the following content:

rustflags = [
  "-C", "link-arg=-undefined",
  "-C", "link-arg=dynamic_lookup",

For developing, you can copy and rename the shared library from the target folder: On MacOS, rename libstring_sum.dylib to string_sum.so, on Windows libstring_sum.dll to string_sum.pyd and on Linux libstring_sum.so to string_sum.so. Then open a Python shell in the same folder and you'll be able to import string_sum.

To build, test and publish your crate as a Python module, you can use pyo3-pack or setuptools-rust. You can find an example for setuptools-rust in examples/word-count, while pyo3-pack should work on your crate without any configuration.

Using Python from Rust

Add pyo3 to your Cargo.toml like this:

pyo3 = "0.7.0"

Example program displaying the value of sys.version and the current user name:

use pyo3::prelude::*;
use pyo3::types::IntoPyDict;

fn main() -> PyResult<()> {
    let gil = Python::acquire_gil();
    let py = gil.python();
    let sys = py.import("sys")?;
    let version: String = sys.get("version")?.extract()?;
    let locals = [("os", py.import("os")?)].into_py_dict(py);
    let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
    let user: String = py.eval(code, None, Some(&locals))?.extract()?;
    println!("Hello {}, I'm Python {}", user, version);

Examples and tooling


PyO3 is licensed under the Apache-2.0 license. Python is licensed under the Python License.


~31K SLoC