Skip to main content

Generate Python .pyi stub files from pyo3-annotated Rust source code statically without compilation

Project description

Rylai

CI

Generate Python .pyi stub files from pyo3-annotated Rust source code — statically, without compilation.

Features

  • Parses #[pymodule], #[pyfunction], and #[pyclass] annotations directly from Rust source
  • Maps Rust types to Python types automatically (i32int, Vec<T>list[T], Option<T>T | None, etc.)
  • Extracts doc comments and emits them as Python docstrings
  • Generates one .pyi file per top-level #[pymodule]
  • Python-version-aware output (T | None for ≥ 3.10, Optional[T] for older)
  • Zero-config by default; optionally configured via rylai.toml

Why Rylai?

Compared with other tools that generate .pyi stubs for PyO3 projects, Rylai offers:

  • No compilation — Rylai parses Rust source code directly (via syn). You don’t need to build the crate or depend on compiled artifacts, so stub generation is fast and works even when the project doesn’t compile (e.g. missing native deps or wrong toolchain).
  • No code changes — No need to add build scripts, #[cfg] blocks, or extra annotations to your Rust code. Point Rylai at your crate root and it reads existing #[pymodule] / #[pyfunction] / #[pyclass] as-is.
  • No Python version lock-in — Stubs are plain text. You generate them once and use them with any Python version; there’s no dependency on a specific Python interpreter or ABI, so you avoid “built for Python 3.x” issues and cross-version workflows stay simple.

Together, this makes Rylai easy to integrate into CI, docs, or local dev without touching your PyO3 code or your Python environment.

Installation

Choose one of the following:

Method Command Notes
Cargo cargo install rylai Build from source and install to ~/.cargo/bin
uv uv tool install rylai Install to uv tools dir; requires publish to PyPI first
uvx uvx rylai Run without installing (same as uv; requires PyPI release)
crgx crgx rylai Run pre-built binary without compiling; requires crgx and a GitHub Release

For local development:

cargo install --path .

Usage

The path you pass is the project root — the folder that contains Cargo.toml (and usually a src/ directory). Rylai scans all .rs files under that project’s src/ and uses the root for rylai.toml, pyproject.toml, etc.

# Run in the current directory (must be the project root with Cargo.toml)
rylai

# Specify the project root explicitly (folder containing Cargo.toml)
rylai path/to/my_crate

# Write stubs to a custom output directory
rylai path/to/my_crate --output path/to/out/

# Use a custom config file
rylai --config path/to/rylai.toml

For developers (this repo)

You don’t need to install the binary. Use cargo run and pass arguments after --:

# Generate stubs for the example crate (writes into examples/pyo3_sample/)
cargo run -- examples/pyo3_sample

# Same as above, with explicit output directory
cargo run -- examples/pyo3_sample --output examples/pyo3_sample

# Show help
cargo run -- --help

Anything after -- is forwarded to the rylai binary.

Example

Given this Rust source (src/lib.rs):

use pyo3::prelude::*;

#[pymodule]
mod pyo3_sample {
    use pyo3::prelude::*;

    /// Formats the sum of two numbers as string.
    #[pyfunction]
    fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
        Ok((a + b).to_string())
    }
}

Rylai produces pyo3_sample.pyi:

# Auto-generated by rylai. Do not edit manually.

# Module: pyo3_sample
def sum_as_string(a: int, b: int) -> str:
    """Formats the sum of two numbers as string."""

Configuration

You can configure rylai in either (or both) of these places:

  • rylai.toml in the crate root
  • [tool.rylai] in pyproject.toml

When both exist, duplicate keys are resolved in favor of rylai.toml; all other options from both files apply. Array tables (e.g. [[override]] / [[tool.rylai.override]]) are replaced as a whole by the same key in rylai.toml, not merged item-by-item. All sections are optional.

Example rylai.toml:

# Root-level keys (e.g. format) should appear before any [section] or [[array]] to avoid being parsed as part of a table.
# After generating .pyi files, run these commands with the generated .pyi paths appended.
# Only use when you trust this config file — commands are executed as configured.
# Each command must be executable (on PATH or use a full path); rylai will error if it cannot be run.
# Empty or whitespace-only entries are ignored.
# You may need "uvx ruff" or "uv/pdm run ruff" instead of "ruff"
format = ["ruff format", "ruff check --select I --fix"]

[output]
# Target Python version — affects Optional[T] vs T | None syntax (default: "3.10")
python_version = "3.10"

# Prepend auto-generated header comment (default: true)
add_header = true

[fallback]
# What to emit when a type cannot be resolved statically:
#   "any"   — emit Any and print a warning (default)
#   "error" — abort with an error
#   "skip"  — silently omit the item
strategy = "any"

[features]
# cfg features to treat as active during parsing
enabled = ["some_feature"]

[type_map]
# Custom Rust type → Python type overrides
"numpy::PyReadonlyArray1" = "numpy.ndarray"
"numpy::PyReadonlyArray2" = "numpy.ndarray"

[[override]]
# Manually written stub for a specific item (takes precedence over generated output)
item = "my_module::complex_function"
stub = "def complex_function(x: Any, **kwargs: Any) -> dict[str, Any]: ..."

The same options can be set in pyproject.toml under [tool.rylai]:

[tool.rylai.output]
python_version = "3.10"

[tool.rylai.fallback]
strategy = "any"

[tool.rylai.type_map]
"numpy::PyReadonlyArray1" = "numpy.ndarray"

[[tool.rylai.override]]
item = "my_module::complex_function"
stub = "def complex_function(x: Any, **kwargs: Any) -> dict[str, Any]: ..."

[tool.rylai]
format = ["isort", "black"]

Supported Type Mappings

Rust type Python type
Scalars
i8i128, u8u128, isize, usize int
f32, f64 float
bool bool
str, String, char str
() None
Bytes
&[u8], [u8] bytes
Vec<u8> bytes
Path-like
Path, PathBuf (incl. std::path::*) Path | str / Union[Path, str]
Containers
Option<T> T | None / Optional[T]
Vec<T> list[T]
(T1, T2, ...) (non-empty tuple) tuple[T1, T2, ...]
HashMap<K,V>, BTreeMap<K,V>, IndexMap<K,V> dict[K, V]
HashSet<T>, BTreeSet<T> set[T]
PyO3 types
PyResult<T>, Result<T, E> T (errors become Python exceptions)
Py<T>, Bound<T>, Borrowed<T> recurse into T
PyRef<T>, PyRefMut<T> recurse into T
PyBytes bytes
PyByteArray bytearray
PyString str
PyDict, PyList, PyTuple, PySet dict, list, tuple, set
PyAny, PyObject Any
Other
Self (in #[pymethods]) Self (py ≥ 3.11) or class name
#[pyclass] structs/enums Python class name (from crate)
Unknown types Any (configurable via [fallback])

Contributing

Before committing, run the pre-commit checks with prek. See CONTRIBUTING.md for details.

License

LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rylai-0.2.0-py3-none-win_amd64.whl (1.5 MB view details)

Uploaded Python 3Windows x86-64

rylai-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

rylai-0.2.0-py3-none-macosx_11_0_arm64.whl (1.3 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

rylai-0.2.0-py3-none-macosx_10_12_x86_64.whl (1.4 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file rylai-0.2.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: rylai-0.2.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rylai-0.2.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 cd9f16c7f45125850ba6163d12f1af6bf955f885c5f763b6f5bf13761b9812e0
MD5 e31670d091dfa73e923698fba63f0c18
BLAKE2b-256 15d16de551728fb666902239bd99d654949fe0eb591f1894bb4b46bf9f7bf2fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for rylai-0.2.0-py3-none-win_amd64.whl:

Publisher: release.yml on monchin/Rylai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rylai-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rylai-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 f8bb7bc92a412e6fc8ecc3e0c0cba1712ff4808ab45fabf029c96c3b51f38364
MD5 fb4412a4ad7394810f1ccab5b64d079c
BLAKE2b-256 edd802b99cd68078a03b8aae94c628ec033e5c0543da12026bb3a66b85d3658b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rylai-0.2.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on monchin/Rylai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rylai-0.2.0-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: rylai-0.2.0-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.3 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for rylai-0.2.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8e03b2f2f2a4653d03e7add2ee9d2562144e4c3c59f5b37f86431049126ef5b5
MD5 a9e000e734f782896b950b21fbeb0adb
BLAKE2b-256 d2f5ee63ff7915807ca528501402f03361aadc9ed1bc03c08367b0cdd20b3f9e

See more details on using hashes here.

Provenance

The following attestation bundles were made for rylai-0.2.0-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on monchin/Rylai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rylai-0.2.0-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for rylai-0.2.0-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ca6d9dac44b432e0c7aff943d47f22e12482389d1e27c938abbfd2069a558903
MD5 2eafcb11bc7438c1ef8d367a146fcc29
BLAKE2b-256 a63e0999f8a752143e0049680289b8dbe6f1d6b2d6d2d6b31a2f8687bf7cfe8b

See more details on using hashes here.

Provenance

The following attestation bundles were made for rylai-0.2.0-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on monchin/Rylai

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page