Summary and Schedule

Python makes it easy to turn an idea into useful software. Rust requires more explicit choices and can provide speed, predictable resource use, and strong compile-time guarantees. This workshop shows how to add Rust at a carefully chosen boundary in an existing Python codebase.

Starting from familiar scripts and notebooks, the workshop examines where a direct translation into Rust stops working. We will build a teaching-sized version of acorn-py with PyO3 and Maturin and see where Rust already appears in the Python ecosystem.

Who is this workshop for?


This workshop is for Python developers who are comfortable writing functions, using collections, importing packages, and working in a terminal. No previous Rust or systems-programming experience is required.

The lesson is especially useful if you want to:

  • speed up a focused part of a Python application;
  • make resource-heavy or concurrent code more predictable;
  • distribute native functionality behind a familiar Python API; or
  • understand the tradeoffs behind the growing number of Rust-backed Python packages.

Learning outcomes


By the end of the workshop, you will be able to:

  • relate common Python constructs, including strings and anonymous functions, to their Rust counterparts;
  • explain ownership, borrowing, traits, and compile-time guarantees in practical terms;
  • identify a suitable boundary for introducing Rust into an existing Python project;
  • expose Rust functions and types to Python with PyO3;
  • build and install an extension module with Maturin;
  • move data and errors across the Python-Rust boundary and test both sides; and
  • choose between example tests, property tests, Miri, model checking, and proof-oriented verification for a specific engineering risk.

The worked example


acorn-py exposes selected APIs from the Rust crates acorn-lib and acorn-schema as the Python module acorn. We begin with the familiar Python contract from acorn.schema.validate import is_doi, trace identifier validation into Rust, add PyO3 functions and classes, translate failures into Python exceptions, and finish by testing a stable-ABI wheel.

The completed project contains more bindings than can be taught in one workshop. Our incremental build follows its real architecture and tooling while concentrating on a representative path: validator function, nested module, Rust-backed identifier type, error mapping, tests, and packaging.

The seven episodes provide 180 minutes of active instruction, exercises, and discussion. Complete the setup before the session so the three hours can focus on design decisions and a working Python-to-Rust vertical slice.

The journey


Stage Focus Destination
There and Back Again Why combine Python and Rust? A grounded reason to use both
Translating Python into Rust Familiar syntax and concepts A first mental map
Where the Analogy Ends Ownership, borrowing, traits, and concurrency Rust’s distinct value
Adding Rust Incrementally Preserve acorn.schema.validate A narrow acorn-py boundary
Building with PyO3 Bind ACORN validators and types Working acorn imports
Crossing the Boundary Data, errors, and tests A tested stable-ABI extension
Practical Guidance Tradeoffs, assurance tools, next steps, and Q&A A route home

Why the boundary stays narrow


Rust adds a compiler toolchain, a native build, and a cross-language boundary. The workshop considers it only for focused work that may justify those costs and preserves a Pythonic interface throughout.

Start with the Setup instructions, then follow the episodes in order. Keep the completed acorn-py checkout as a reference while building the teaching version at each checkpoint.

The actual schedule may vary slightly depending on the topics and exercises chosen by the instructor.

Complete this setup before the workshop. We will use acorn-py as one continuous example: first as a Python-facing identifier-validation API, then as a Rust library exposed through PyO3, and finally as a tested wheel built with Maturin.

The completed acorn-py repository is our reference implementation. During the workshop we will build a smaller teaching version of it one layer at a time.

Plan 20 to 30 minutes for the first setup. Pixi and Cargo must download the locked Python packages, Rust toolchain, and Rust crates before the first build.

What you need to install


Install these system-level tools:

  • Git, to clone acorn-py and fetch its pinned ACORN Rust dependencies;
  • Pixi, which installs the project-specific Python, Rust, Maturin, pytest, Ruff, and native build dependencies; and
  • a platform linker and build tools, described below.

The locked environment already includes Python, Rust, Maturin, and pytest, so you do not need to install them or create a separate virtual environment. The committed pixi.lock and Cargo.lock files define the workshop environment.

Check Git before continuing:

git --version

Platform build tools

Choose your operating system once. The other operating-system tabs on this page will follow your selection.

Install Pixi


Follow the official Pixi installation instructions for your operating system.

Open a new terminal so the updated PATH takes effect.

Confirm that Pixi is available:

pixi --version

Get the reference project


Choose a directory where you keep source code, then clone acorn-py:

git clone https://code.ornl.gov/research-enablement/acorn-py.git
cd acorn-py

Do not clone the larger ACORN repository separately. Cargo fetches the acorn-lib and acorn-schema crates from the immutable Git revision recorded in Cargo.toml and Cargo.lock.

The names intentionally differ:

  • the repository and Python distribution are named acorn-py;
  • the Rust crate is named acorn-py; and
  • Python code imports the extension as acorn.

We will revisit that packaging boundary during the PyO3 episode.

Create the locked environments


From the root of the cloned acorn-py repository, install both supported test environments:

pixi install --locked -e py310
pixi install --locked -e py313

These environments are declared in pyproject.toml. At the time this lesson was prepared, they selected:

Component Project requirement
Python 3.10 and 3.13 test environments; package minimum 3.10
Rust 1.96.x
Maturin 1.9.x
PyO3 0.28.x with abi3-py310 and extension-module
pytest 8.4.x

Use the versions resolved by pixi.lock if its exact patch versions differ from this table. Do not run pixi update or cargo update during the workshop.

Verify the development build


Build the extension into the Python 3.13 development environment and run the Python test suite:

pixi run -e py313 test

The test task creates a development environment, runs maturin develop --uv --locked, and then runs pytest. The first invocation also compiles the pinned ACORN crates and can take several minutes.

Verify the Python-facing API directly:

pixi run -e py313 python -c "from acorn.schema.validate import is_doi; assert is_doi('10.11578/dc.20250604.1'); print('acorn-py is ready')"

The command should print acorn-py is ready.

Run the complete pre-workshop check


This sequence checks formatting and lints, tests the extension with Python 3.10 and 3.13, builds its stable-ABI wheel, installs that wheel into a clean environment, imports acorn, and checks the acorn-py distribution metadata.

If a command fails, save the complete output and send it to an instructor before the workshop.

Callout

Network and managed-system requirements

Initial setup needs HTTPS access to Conda Forge, PyPI, crates.io, and code.ornl.gov. The build does not require a separate ACORN executable, model, service, credential, or local ACORN checkout.

On managed or offline systems, ask local support to allow or pre-cache these dependencies. Linux hosts with an unusual glibc version may also need a platform-specific Pixi system-requirements setting. Send the output of pixi info to an instructor and leave the committed lockfile unchanged.

Optional editor support


Any text editor works. For Visual Studio Code, the Python and rust-analyzer extensions provide Python completion and inline Rust compiler feedback. Opening the editor from pixi shell -e py313 can help it discover the project-managed tools.