Skip to content

Latest commit

 

History

History
135 lines (101 loc) · 5.64 KB

File metadata and controls

135 lines (101 loc) · 5.64 KB

Usage with setup.py

While pyproject.toml-based configuration will be enough for most projects, sometimes you may need to use custom logic and imperative programming during the build. For those scenarios, setuptools also allows you to specify project configuration via setup.py in addition to pyproject.toml.

The following is a very basic tutorial that shows how to use setuptools-rust in your setup.py.

Basic implementation files

Let's start by assuming that you already have a bunch of Python and Rust files1 that you would like to package for distribution in PyPI inside of a project directory named hello-world-setuppy23:

hello-world-setuppy
├── Cargo.lock
├── Cargo.toml
├── python
│   └── hello_world
│       └── __init__.py
└── rust
    └── lib.rs
   :language: python
   :language: rust
   :language: toml

Adding files to support packaging

Now we start by adding a pyproject.toml which tells anyone that wants to use our project to use setuptools and setuptools-rust to build it:

   :language: toml

… and a setup.py configuration file that tells Setuptools how to build the Rust extensions using our Cargo.toml and setuptools-rust:

   :language: python

For a complete reference of the options supported by the RustExtension class, see the API reference.

We also add a MANIFEST.in file to control which files we want in the source distribution4:

Testing the extension

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-setuppy
python3 -m venv .venv
source .venv/bin/activate  # on Linux or macOS
.venv\Scripts\activate     # on Windows
python -m pip install -e .
python -c 'import hello_world; print(hello_world.sum_as_string(5, 7))'  # => 12
# ... better write some tests with pytest ...

Next steps and final remarks

  • When you are ready to distribute your project, have a look on the notes in the documentation about building wheels.

  • You can also use a RustBin object (instead of a RustExtension), if you want to distribute a binary executable written in Rust (instead of a library that can be imported by the Python runtime). Note however that distributing both library and executable (or multiple executables), may significantly increase the size of the wheel file distributed by the package index and therefore increase build, download and installation times. Another approach is to use a Python entry-point that calls the Rust implementation (exposed via PyO3 bindings). See the hello-world example for more insights.

  • If want to include both RustBin and RustExtension same macOS wheel, you might have to manually add an extra build.rs file, see PyO3/setuptools-rust#351 for more information about the workaround.

  • If your Rust extension generates files as part of its build.rs build script that you want to be present in your Python wheel, you can use the generated_files argument of RustExtension to define which files should be copied across, and into which locations in the Python package.

  • Since the adoption of {pep}517, running python setup.py ... directly as a CLI tool is considered deprecated. Nevertheless, setup.py can be safely used as a configuration file (the same way conftest.py is used by pytest or noxfile.py is used by nox). There is a different mindset that comes with this change, though: for example, it does not make sense to use sys.exit(0) in a setup.py file or use a overarching try...except... block to re-run a failed build with different parameters.

Footnotes

  1. To know more about how to write Rust to be integrated into Python packages, please have a look on the PyO3 docs

  2. You can have a look on the examples/hello-world-setuppy directory in the setuptools-rust repository.

  3. If you are an experienced Python or Rust programmer, you may notice that we avoid using the src directory and explicitly instruct Setuptools and Cargo to look into the python and rust directories respectively. Since both Python and Rust ecosystem will try to claim the src directory as their default, we prefer to be explicit and avoid confusion.

  4. Alternatively you can also use setuptools-scm to add all the files under revision control to the sdist, see the docs for more information.