pyo3_bindgen

pyo3_bindgen generates Rust bindings to Python modules via PyO3. It walks a module recursively and mirrors its public classes, functions, properties and constants in Rust, keeping docstrings and type annotations. Rust then calls Python through typed functions instead of string lookups, which helps to integrate a Python project with Rust or to port it step by step.

For a small orbit.py module, pyo3_bindgen -m orbit turns float annotations into f64 and docstrings into Rust doc comments, and gives the module constant MU_EARTH a getter and a setter.

Live demo

The pyo3_bindgen playground with a Python module beside the Rust bindings generated for itThe pyo3_bindgen playground with a Python module beside the Rust bindings generated for it

Edit Python or name any module, including packages from PyPI, to see the Rust that calls it, then compile and run a program that uses the bindings. Pyodide runs Python, the generator is compiled to WebAssembly, and the Rust compiler runs in a Linux virtual machine in your browser.

Features

  • Build script: call pyo3_bindgen::Codegen from build.rs, optionally customized with pyo3_bindgen::Config, and include! the generated file.
  • Procedural macro (experimental): import_python!("math") with the macros feature generates bindings in place.
  • Command line: cargo install --locked pyo3_bindgen_cli, then pyo3_bindgen -m os sys numpy -o bindings.rs to inspect bindings for any importable module.
  • NumPy (experimental): the numpy feature maps NumPy arrays to the numpy crate’s PyArray.
  • In use: the upcoming version of blr generates its typed bindings to Blender with it.

Status

The latest release is pyo3_bindgen 0.5.0 (May 2024) on crates.io, dual-licensed under MIT or Apache 2.0. It targets the Bound<'py, T> API introduced in PyO3 0.21; version 0.4 remains available for the older GIL-Refs API. The playground already runs the upcoming 0.6.0.

The generated code still calls into Python, so it is not faster by itself; it is a typed starting point for rewriting the slow parts in Rust. Bindings are only as complete as a module’s structure, annotations and docstrings. Not every Python type has a Rust mapping yet, and the API of the generated bindings may still change.