liveBook · Manning

Pymodule attribute

As explained in Refactoring to Rust

The PyO3 pymodule attribute macro defines a Rust function as the initializer for a Python extension module.

The PyO3 `pymodule` attribute marks a Rust function as the initializer for a Python extension module. The function receives a Python interpreter handle and module object, then returns `PyResult<()>` after registering the module's contents. section 6.4 section 8.6

A minimal initializer can be empty, but useful modules add exported functions with `wrap_pyfunction!`. The resulting Rust library can be imported like an ordinary Python module while keeping its public API in Python. section 6.4 section 8.6

Registering a function

Mark `sum` with `#[pyfunction]`, then register it inside the initializer: `m.add_function(wrap_pyfunction!(sum, m)?)?;`. After building with maturin, Python can run `rust_json.sum(...)` just like a normal imported function. section 6.4

A compute module

A Mandelbrot extension uses `#[pymodule] fn mandelbrot(...)` to register `mandelbrot_func`. Python imports that module and submits the Rust function through a thread executor; a separate exported function can release the GIL for concurrency. section 8.6

Listing 6.9 Empty extension module
use pyo3::prelude::*;

#[derive(Debug, serde::Deserialize)]
struct Data {
  name: String,
  value: i32,
}

fn sum(input: &str) -> i32 {
  let parsed: Data = serde_json::from_str(input).unwrap();

  parsed.name.len() as i32 + parsed.value
}

#[pymodule]
fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> {
  Ok(())
}

Shows the smallest complete extension-module initializer alongside Rust code that is not yet exported. section 6.4

Listing 8.9 lib.rs: Creating the Python module
#[pymodule]  #1
fn mandelbrot(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(mandelbrot_func, m)?)?;  #2

    Ok(())
}

Shows the practical pattern for creating a module and registering a PyO3 function. section 8.6

How Refactoring to Rust covers it

How deep it goes
Explains the initializer signature and registration pattern, but defers broader PyO3 bindings and detailed macro internals.
Examples
Uses the rust_json sum module and a Mandelbrot image generator to demonstrate imports, registration, and threaded execution.
What it assumes
Assumes basic Rust and Python familiarity while introducing extension-module structure, PyO3 setup, and Rust-library conversion.
What you can do after
Build it from scratch by marking a Rust initializer, registering PyO3 functions, compiling with maturin, and importing the module from Python.
How it connects
Connects Python extension modules with PyO3, pyfunction macros, maturin, and the Python GIL.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.