Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
pyo3-gated
Write Rust types once. Use them natively in Rust and optionally expose them to Python via PyO3 without duplicate definitions.
Quick Start
[]
= { = "^0.1", = ["python"] }
[]
= []
= ["pyo3-gated/stub-gen"]
= [
"pyo3-gated/python",
]
use *;
define_pyo3_gated_stub_info!;
define_py_module!
cargo build compiles with pyo3-gated's owned PyO3 dependency when python is enabled. cargo run --bin stub_gen --features stub-gen enables pyo3-stub-gen registration and stub output. Downstream crates do not need to depend on pyo3 directly; use pyo3_gated::pyo3 when explicit PyO3 types are needed.
Use maturin for wheel builds. It sets PyO3's extension-module build environment for normal extension builds, so new projects should not add pyo3-gated/generate-import-lib by default.
Before opening a PR, run scripts/check.sh. If your change affects stub generation, run scripts/stub-check.sh too.
Feature Model
pyo3-gated assumes a Cargo feature named python by default.
[]
= "^0.1"
[]
= []
= ["pyo3-gated/python"]
= ["python", "pyo3-gated/stub-gen"]
= [
"python",
]
pyo3-gated/python enables the facade's owned PyO3 dependency. PyO3 features are exposed as pyo3-gated pass-through features such as extension-module, abi3-py315, abi3t, abi3t-py315, anyhow, and other conversion features.
extension-module and generate-import-lib remain available as compatibility pass-throughs. For new extension builds, prefer maturin or set PYO3_BUILD_EXTENSION_MODULE=1 directly when invoking Cargo. generate-import-lib is deprecated upstream in PyO3 0.29 and should not be part of new project templates.
Build Recipes
# Plain Rust build: no PyO3 dependency needed
# Python-aware Rust build
# Extension-module build
PYO3_BUILD_EXTENSION_MODULE=1
# Build and install the example module with maturin
# Generate stubs
Macros
| Macro | Applies to |
|---|---|
py_compat |
dispatches over structs, enums, inherent impl blocks, and free functions |
py_compat_struct |
struct definitions |
py_compat_enum |
simple and complex enum definitions |
py_compat_methods |
inherent impl blocks |
py_compat_fn |
free functions |
define_py_module! |
cfg-gated PyO3 module registration |
Each macro emits two cfg-gated versions:
| Build | Output |
|---|---|
feature = "python" |
PyO3-annotated item |
feature = "stub-gen" |
stub-gen registration attributes |
no python feature |
plain Rust item with PyO3 and stub-gen attributes stripped |
Method Sentinels
Inside #[py_compat_methods], use these item-level marker attributes:
| Attribute | Effect |
|---|---|
#[py_only] |
method exists only in Python builds |
#[rust_only] |
method exists only in plain Rust builds and is not exposed to Python |
#[py_attrs] |
method exists in both builds, but Python-specific attributes are stripped in plain builds |
Combining #[py_only], #[rust_only], and #[py_attrs] on the same item is a compile error.
Only functions are exposed to PyO3 from #[py_compat_methods]. Associated consts, associated types, and macro items must be marked #[rust_only] or moved outside the PyO3-managed impl block.
Macro Arguments
| Argument | Values | Default | Purpose |
|---|---|---|---|
feature |
"feature-name" |
"python" |
Which Cargo feature enables the Python build |
stub_gen |
false, true, or "feature-name" |
"stub-gen" |
Controls automatic stub-registration derive emission |
pyclass_args |
token tree | none | Forwarded into #[pyclass(...)] |
pyfunction_args |
token tree | none | Forwarded into #[pyfunction(...)] |
pyo3_crate |
Rust path string | resolved from Cargo metadata | Override PyO3 crate path, for renamed or re-exported PyO3 |
py_only |
flag | false | Free function exists only in Python builds |
Stub registration is enabled by default under a Cargo feature named stub-gen. Disable it for one item when needed:
Use a custom Python feature name:
Forward PyO3 class options:
Forward PyO3 function options:
Use a Python-only free function when its signature uses PyO3 types:
use pyo3;
Register a module without handwritten cfg boilerplate:
define_py_module!
For unusual dependency layouts, override the PyO3 path:
Stub Generation
The macros choose the correct pyo3-stub-gen derive automatically:
| Item | Stub derive |
|---|---|
| struct | gen_stub_pyclass |
| simple enum | gen_stub_pyclass_enum |
| complex enum | gen_stub_pyclass_complex_enum |
| impl block | gen_stub_pymethods |
| free function | gen_stub_pyfunction |
Define the gatherer once in your library:
define_pyo3_gated_stub_info!;
The older compatibility alias is still available:
define_stub_info_gatherer!;
define_pyo3_gated_stub_info! is the preferred macro. define_stub_info_gatherer! remains as a compatibility alias.
Then gate your stub-generation binary with stub-gen:
[[]]
= "stub_gen"
= "src/bin/stub_gen.rs"
= ["stub-gen"]
Advanced stub-generation APIs are available under pyo3_gated::stub_gen when stub-gen is enabled.
Compatibility Policy
pyo3-gated version |
Supported pyo3 range |
Bundled pyo3-stub-gen |
|---|---|---|
0.1.x |
0.29 |
0.23.0 |
pyo3-gated owns and re-exports PyO3. The stub-gen feature uses the pyo3-stub-gen version bundled by pyo3-gated, so stub-generation support is tied to the PyO3 version supported by that pyo3-stub-gen release. PyO3 0.29 supports Python 3.8+ and no longer supports Python 3.7. Run stub-generation flows on Python 3.10+.
PyO3 0.29 pass-through features include abi3-py315, abi3t, and abi3t-py315. ABI-selection features are exposed individually and are not included in full.
Use cargo tree -d --workspace --features stub-gen and cargo tree --workspace --features stub-gen -i pyo3 to verify that your workspace resolves a single compatible PyO3 version.
Troubleshooting
Explicit PyO3 types fail to resolve: import PyO3 through the facade with use pyo3_gated::pyo3;. A direct pyo3 dependency is not required for normal use and can create version conflicts if it is incompatible.
Duplicate PyO3 versions after upgrading: remove direct pyo3 dependencies unless they are intentional, or update them to the same PyO3 line as pyo3-gated. Check the result with cargo tree -i pyo3.
StubGenResult not found: build the stub binary with the downstream stub-gen feature and wire that feature to pyo3-gated/stub-gen. Stub binaries should usually declare required-features = ["stub-gen"].
Python-specific types fail in plain Rust builds: #[py_attrs] strips attributes, not Rust types. Methods taking Python<'_>, Bound<'_, PyAny>, PyResult<T>, or other PyO3 types should be #[py_only] or manually cfg-gated.
Missing .pyi content: confirm the item did not use stub_gen = false, the stub binary is run with --features stub-gen, and pyclass_args(module = "...") matches the module layout you expect.
Migration From Raw PyO3
Before:
After:
Rust-Only Crates
Rust-only users only need:
[]
= "^0.1"
PyO3 field, variant, and function attributes are stripped from the plain build, so no PyO3 dependency is compiled unless the Python feature is enabled.
Current Limitations
#[py_compat_methods]supports inherentimpl Type { ... }blocks, not trait impls.- Users should not manually add
#[pyclass],#[pymethods],#[pyfunction], or#[pymodule]to items managed by these macros; the macros add them. - Python builds use the PyO3 version and feature set exposed by
pyo3-gated. - Python-specific argument and return types still require cfg control for plain Rust builds.
pyo3-gateddoes not chooseabi3,extension-module,auto-initialize, or conversion features for you.- Generic PyO3 classes and complex enums remain subject to PyO3 and
pyo3-stub-genlimitations. - Stub generation requires project metadata such as
pyproject.tomlwhen generating package-oriented stubs.
License
MIT