GitHub - PyO3/setuptools-rust: Setuptools plugin for Rust support (original) (raw)

Setuptools plugin for Rust extensions

github actions pypi package readthedocs Ruff

setuptools-rust is a plugin for setuptools to build Rust Python extensions implemented with PyO3 or rust-cpython.

Compile and distribute Python extensions written in Rust as easily as if they were written in C.

Quickstart

The following is a very basic tutorial that shows how to use setuptools-rust in pyproject.toml. It assumes that you already have a bunch of Python and Rust files that you want to distribute. You can see examples for these files in theexamples/hello-worlddirectory in the github repository. The PyO3 docs have detailed information on how to write Python modules in Rust.

hello-world
├── python
│   └── hello_world
│       └── __init__.py
└── rust
    └── lib.rs

Once the implementation files are in place, we need to add a pyproject.tomlfile that tells anyone that wants to use your project how to build it. In this file, we use an array of tables(TOML jargon equivalent to Python's list of dicts) for [[tool.setuptools-rust.ext-modules]], to specify different extension modules written in Rust:

pyproject.toml

[build-system] requires = ["setuptools", "setuptools-rust"] build-backend = "setuptools.build_meta"

[project] name = "hello-world" version = "1.0"

[tool.setuptools.packages]

Pure Python packages/modules

find = { where = ["python"] }

[[tool.setuptools-rust.ext-modules]]

Private Rust extension module to be nested into the Python package

target = "hello_world._lib" # The last part of the name (e.g. "_lib") has to match lib.name in Cargo.toml, # but you can add a prefix to nest it inside of a Python package. path = "Cargo.toml" # Default value, can be omitted binding = "PyO3" # Default value, can be omitted

Each extension module should map directly into the corresponding [lib] table on theCargo manifest file:

Cargo.toml

[package] name = "hello-world" version = "0.1.0" edition = "2021"

[dependencies] pyo3 = "0.24"

[lib] name = "_lib" # private module to be nested into Python package, # needs to match the name of the function with the [#pymodule] attribute path = "rust/lib.rs" crate-type = ["cdylib"] # required for shared library for Python to import from.

See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

See also PyO3 docs on writing Cargo.toml files at https://pyo3.rs

You will also need to tell Setuptools that the Rust files are required to build your project from the source distribution. That can be done either via MANIFEST.in (see example below) or via a plugin likesetuptools-scm.

# MANIFEST.in
include Cargo.toml
recursive-include rust *.rs

With these files in place, you can install the project in a virtual environment for testing and making sure everything is working correctly:

cd hello-world

python3 -m venv .venv source .venv/bin/activate # on Linux or macOS .venv\Scripts\activate # on Windows python -m pip install -e . python

import hello_world

... try running something from your new extension module ...

... better write some tests with pytest ...

Environment variables for configuration

As well as all environment variables supported by Cargo, setuptools-rust also supports the following:

Next steps and final remarks