PyO3 / PyO3/pyo3

`experimental-inspect`: `__all__` is set at runtime by `#[pymodule]` but never emitted into the stubs

Open
#6,241 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
16.2k
Forks
1k
Avg merge
2d 6h
Merged PRs (30d)
66

Description

Bug Description

PyModuleMethods::add appends every added name to the module's __all__
(src/types/module.rs:500), so
every #[pymodule] has an __all__ at runtime. pyo3-introspection never emits one, so the stub
and the runtime disagree and mypy.stubtest reports one error per module:

error: allrepro.__all__ is not present in stub
Stub: in file .../allrepro/__init__.pyi
MISSING
Runtime: in file .../allrepro/__init__.py
<module 'allrepro' ...>

This matters beyond stubtest: without __all__, type checkers apply the implicit re-export
rules to the stub, which is not what the runtime module actually exports.

On pyo3_pytests this accounts for 15 of the 43 stubtest errors that block #6240.

Steps to Reproduce
  1. Build an extension with the experimental-inspect feature:

    use pyo3::prelude::*;
    
    #[pymodule]
    mod allrepro {
        use pyo3::prelude::*;
    
        #[pyclass]
        pub struct Thing;
    
        #[pyfunction]
        pub fn helper() -> usize { 1 }
    }
    
  2. maturin develop, then
    cargo run -p pyo3-introspection -- <path to .so> allrepro stubs

  3. The runtime has __all__, the generated stubs/__init__.pyi does not:

    >>> import allrepro; allrepro.__all__
    ['Thing', 'helper']
    
    # stubs/__init__.pyi
    from typing import final
    
    @final
    class Thing: ...
    
    def helper() -> int: ...
    
  4. Copy the .pyi next to the extension, touch py.typed, run python -m mypy.stubtest allrepro.

Backtrace

Your operating system and version

Linux (CachyOS, kernel 7.1.3)

Your Python version (python --version)

Python 3.13.14

Your Rust version (rustc --version)

rustc 1.96.0 (ac68faa20 2026-05-25)

Your PyO3 version

0.29.0 (main)

How did you install python? Did you use a virtualenv?

uv (uv venv --python 3.13)

Additional Info

The contents are already available to the generator: Module in
pyo3-introspection/src/model.rs carries modules, classes, functions and attributes, and
those match the runtime __all__ exactly in the cases checked. So module_stubs
(stubs.rs:49)
should be able to emit __all__ = [...] without new introspection data.

Open question — incomplete modules. Modules with a #[pymodule_init] are tagged incomplete and
get a def __getattr__(name: str) -> Incomplete: ... marker instead of a full listing. Emitting
__all__ for those asserts a completeness the introspector cannot verify, since a
#[pymodule_init] may add further exports. Options: emit it regardless, omit it for incomplete
modules (leaving the stubtest error in place), or emit a bare __all__: list[str] declaration.

Tested with stubtest 2.3.0.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in pyo3-introspection/src/stubs.rs at module_stubs and inspect the Module data in pyo3-introspection/src/model.rs, including how incomplete modules are represented. Reproduce the generated stubs from the issue and run mypy.stubtest against the extension. Done means the stubs' all behavior matches runtime modules, with an explicit resolution for incomplete modules.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.