Introduction - PyO3 user guide

Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The PyO3 user guide

Welcome to the PyO3 user guide! This book is a companion to

PyO3’s API docs

. It contains examples and documentation to explain all of PyO3’s use cases in detail.

The rough order of material in this user guide is as follows:

Getting started

Wrapping Rust code for use from Python

How to use Python code from Rust

Remaining topics which go into advanced concepts in detail

Please choose from the chapters on the left to jump to individual topics, or continue below to start with PyO3’s README.

———

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

Requires Rust 1.83 or greater.

PyO3 supports the following Python distributions:

CPython 3.8 or greater

PyPy 7.3 (Python 3.11+)

GraalPy 25.0 or greater (Python 3.12+)

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 = "2021" [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 = "0.29.2" src/lib.rs

/// A Python module implemented in Rust. The name of this module must match /// the `lib.name` setting in the `Cargo.toml`, else Python will not be able to /// import the module. #[pyo3::pymodule] mod string_sum { use pyo3::prelude::*; /// Formats the sum of two numbers as string. #[pyfunction] fn sum_as_string(a: usize, b: usize) -> PyResult<String> { Ok((a + b).to_string()) } }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' When checking runtime performance, run maturin develop --release to build with optimizations.

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):

mkdir string_sum && cd "$_" python -m venv .env source .env/bin/activate pip install maturin maturin init --bindings pyo3 maturin develop 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.29.2" # Enabling this cargo feature will cause PyO3 to start a Python interpreter on first call to `Python::attach` features = ["auto-initialize"] Example program displaying the value of sys.version and the current user name:

use pyo3::prelude::*; use pyo3::types::IntoPyDict; fn main() -> PyResult<()> { Python::attach(|py| { let sys = py.import("sys")?; let version: String = sys.getattr("version")?.extract()?; let locals = [("os", py.import("os")?)].into_py_dict(py)?; let code = c"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); Ok(()) }) }The guide has

a section

with lots of examples about this topic.

Tools and libraries

maturin

Build and publish crates with pyo3, rust-cpython or cffi bindings as well as rust binaries as python packages

setuptools-rust

Setuptools plugin for Rust support.

pyo3-built

Simple macro to expose metadata obtained with the

built

crate as a

PyDict

rust-numpy

Rust binding of NumPy C-API

dict-derive

Derive FromPyObject to automatically transform Python dicts into Rust structs

pyo3-log

Bridge from Rust to Python logging

pythonize

Serde serializer for converting Rust objects to JSON-compatible Python objects

pyo3-async-runtimes

Utilities for interoperability with Python’s Asyncio library and Rust’s async runtimes.

rustimport

Directly import Rust files or crates from Python, without manual compilation step. Provides pyo3 integration by default and generates pyo3 binding code automatically.

pyo3-arrow

Lightweight

Apache Arrow

integration for pyo3.

pyo3-bytes

Integration between

bytes

and pyo3.

pyo3-object_store

Integration between

object_store

and

pyo3

.

Examples

anise

A modern, high-performance toolkit for spacecraft mission design, notably used to help softly land Firefly Blue Ghost on the Moon on 02 Feb 2025.

arro3

A minimal Python library for Apache Arrow, connecting to the Rust arrow crate.

arro3-compute

arro3-compute

arro3-core

arro3-core

arro3-io

arro3-io

bed-reader

Read and write the PLINK BED format, simply and efficiently.Shows Rayon/ndarray::parallel (including capturing errors, controlling thread num), Python types to Rust generics, Github Actions

blake3-py

Python bindings for the

BLAKE3

cryptographic hash function.Parallelized

builds

on GitHub Actions for MacOS, Linux, Windows, including free-threaded 3.13t wheels.

cellular_raza

A cellular agent-based simulation framework for building complex models from a clean slate.

connector-x

Fastest library to load data from DB to DataFrames in Rust and Python.

cryptography

Python cryptography library with some functionality in Rust.

css-inline

CSS inlining for Python implemented in Rust.

datafusion-python

A Python library that binds to Apache Arrow in-memory query engine DataFusion.

deltalake-python

Native Delta Lake Python binding based on delta-rs with Pandas integration.

fastbloom

A fast

bloom filter

|

counting bloom filter

implemented by Rust for Rust and Python!

fastuuid

Python bindings to Rust’s UUID library.

fast-paseto

High-performance PASETO (Platform-Agnostic Security Tokens) implementation with Python bindings.

feos

Lightning fast thermodynamic modeling in Rust with fully developed Python interface.

finalytics

Investment Analysis library in Rust | Python.

forust

A lightweight gradient boosted decision tree library written in Rust.

geo-index

A Rust crate and

Python library

for packed, immutable, zero-copy spatial indexes.

granian

A Rust HTTP server for Python applications.

haem

A Python library for working on Bioinformatics problems.

hifitime

A high fidelity time management library for engineering and scientific applications where general relativity and time dilation matter.

html2text-rs

Python library for converting HTML to markup or plain text.

html-py-ever

Using

html5ever

through

kuchiki

to speed up html parsing and css-selecting.

hudi-rs

The native Rust implementation for Apache Hudi, with C++ & Python API bindings.

inline-python

Inline Python code directly in your Rust code.

johnnycanencrypt

OpenPGP library with Yubikey support.

jsonschema

A high-performance JSON Schema validator for Python.

mocpy

Astronomical Python library offering data structures for describing any arbitrary coverage regions on the unit sphere.

obstore

The simplest, highest-throughput Python interface to Amazon S3, Google Cloud Storage, Azure Storage, & other S3-compliant APIs, powered by Rust.

opendal

A data access layer that allows users to easily and efficiently retrieve data from various storage services in a unified way.

orjson

Fast Python JSON library.

ormsgpack

Fast Python msgpack library.

pdfcrate

An ergonomic, high-level PDF generation library for Rust and Python — a Prawn-style layout API for composing documents, not low-level PDF plumbing.

polars

Fast multi-threaded DataFrame library in Rust | Python | Node.js.

pycrdt

Python bindings for the Rust CRDT implementation

Yrs

.

pydantic-core

Core validation logic for pydantic written in Rust.

primp

The fastest python HTTP client that can impersonate web browsers by mimicking their headers and TLS/JA3/JA4/HTTP2 fingerprints.

quebec

A database-backed background job queue for Python, inspired by Rails’ Solid Queue.

radiate

: A high-performance evolution engine for genetic programming and evolutionary algorithms.

rateslib

A fixed income library for Python using Rust extensions.

river

Online machine learning in python, the computationally heavy statistics algorithms are implemented in Rust.

robyn

A Super Fast Async Python Web Framework with a Rust runtime.

rust-python-coverage

Example PyO3 project with automated test coverage for Rust and Python.

rnet

Asynchronous Python HTTP Client with Black Magic

sail

Unifying stream, batch, and AI workloads with Apache Spark compatibility.

tibs

A sleek Python library for binary data.

tiktoken

A fast BPE tokeniser for use with OpenAI’s models.

tokenizers

Python bindings to the Hugging Face tokenizers (NLP) written in Rust.

tzfpy

A fast package to convert longitude/latitude to timezone name.

toml-rs

A High-Performance TOML v1.0.0 and v1.1.0 parser for Python written in Rust.

utiles

Fast Python web-map tile utilities

Articles and other media

(Video) Using Rust in Free-Threaded vs Regular Python 3.13

- Jun 4, 2025

(Video) Techniques learned from five years finding the way for Rust in Python

- Feb 26, 2025

(Podcast) Bridging Python and Rust: An Interview with PyO3 Maintainer David Hewitt

- Aug 30, 2024

(Video) PyO3: From Python to Rust and Back Again

- Jul 3, 2024

Parsing Python ASTs 20x Faster with Rust

- Jun 17, 2024

(Video) How Python Harnesses Rust through PyO3

- May 18, 2024

(Video) Combining Rust and Python: The Best of Both Worlds?

- Mar 1, 2024

(Video) Extending Python with Rust using PyO3

- Dec 16, 2023

A Week of PyO3 + rust-numpy (How to Speed Up Your Data Pipeline X Times)

- Jun 6, 2023

(Podcast) PyO3 with David Hewitt

- May 19, 2023

Making Python 100x faster with less than 100 lines of Rust

- Mar 28, 2023

How Pydantic V2 leverages Rust’s Superpowers

- Feb 4, 2023

How we extended the River stats module with Rust using PyO3

- Dec 23, 2022

Nine Rules for Writing Python Extensions in Rust

- Dec 31, 2021

Calling Rust from Python using PyO3

- Nov 18, 2021

davidhewitt’s 2021 talk at Rust Manchester meetup

- Aug 19, 2021

Incrementally porting a small Python project to Rust

- Apr 29, 2021

Vortexa - Integrating Rust into Python

- Apr 12, 2021

Writing and publishing a Python module in Rust

- Aug 2, 2020

Contributing

Everyone is welcomed to contribute to PyO3! There are many ways to support the project, such as:

help PyO3 users with issues on GitHub and

Discord

improve documentation

write features and bugfixes

publish blogs and examples of how to use PyO3

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:

davidhewitt

messense

License

PyO3 is licensed under the

Apache-2.0 license

or the

MIT license

, at your option.

Python is licensed under the

Python License

.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in PyO3 by you, as defined in the Apache License, shall be dual-licensed as above, without any additional terms or conditions.