`experimental-inspect`: `PyList` / `PyDict` / `PyTuple` emit bare `list` / `dict` / `tuple`, which fail `mypy --strict`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 16.2k
- Forks
- 1k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 66
Description
Bug Description
Summary
pyo3-introspection annotates the concrete container types Bound<'_, PyList>, Bound<'_, PyDict>, Bound<'_, PyTuple> (and their Py<...> equivalents) as the bare generics list, dict, tuple:
def make_list() -> list: ...
def take_dict(_x: dict) -> None: ...
Bare generics are rejected by mypy --strict, because --strict turns on disallow_any_generics:
error: Missing type arguments for generic type "list" [type-arg]
So any stub that mentions one of these container types is not --strict-clean out of the box. PyO3 already knows the container kind; emitting the element-agnostic parametrization (list[Any], dict[Any, Any], tuple[Any, ...]) means exactly the same thing and passes --strict.
Steps to Reproduce
Minimal reproduction
Cargo.toml:
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
pyo3 = { version = "0.29", features = ["abi3-py312", "extension-module", "experimental-inspect"] }
src/lib.rs:
use pyo3::prelude::*;
use pyo3::types::{PyDict, PyList, PyTuple};
#[pyfunction] fn take_list(_x: Bound<'_, PyList>) {}
#[pyfunction] fn make_list(py: Python<'_>) -> Bound<'_, PyList> { PyList::empty(py) }
#[pyfunction] fn take_dict(_x: Bound<'_, PyDict>) {}
#[pyfunction] fn make_dict(py: Python<'_>) -> Bound<'_, PyDict> { PyDict::new(py) }
#[pyfunction] fn take_tuple(_x: Bound<'_, PyTuple>) {}
#[pyfunction] fn make_tuple(py: Python<'_>) -> PyResult<Bound<'_, PyTuple>> { PyTuple::new(py, [1, 2, 3]) }
#[pymodule]
mod baregen_repro {
#[pymodule_export]
use super::{make_dict, make_list, make_tuple, take_dict, take_list, take_tuple};
}
Generated stub (module_stub_files)
def make_dict() -> dict: ...
def make_list() -> list: ...
def make_tuple() -> tuple: ...
def take_dict(_x: dict) -> None: ...
def take_list(_x: list) -> None: ...
def take_tuple(_x: tuple) -> None: ...
mypy --strict output
Running mypy --strict on the generated stub (no other config):
baregen_repro.pyi:1: error: Missing type arguments for generic type "dict" [type-arg]
baregen_repro.pyi:2: error: Missing type arguments for generic type "list" [type-arg]
baregen_repro.pyi:3: error: Missing type arguments for generic type "tuple" [type-arg]
baregen_repro.pyi:4: error: Missing type arguments for generic type "dict" [type-arg]
baregen_repro.pyi:5: error: Missing type arguments for generic type "list" [type-arg]
baregen_repro.pyi:6: error: Missing type arguments for generic type "tuple" [type-arg]
Found 6 errors in 1 file
Backtrace
Your operating system and version
Linux
Your Python version (python --version)
3.14.6
Your Rust version (rustc --version)
1.96.0
Your PyO3 version
0.29.0
How did you install python? Did you use a virtualenv?
uv
Additional Info
Suggested fix
Emit the element-agnostic parametrization for these container types:
| Rust type | current | proposed |
|---|---|---|
PyList |
list |
list[Any] |
PyDict |
dict |
dict[Any, Any] |
PyTuple |
tuple |
tuple[Any, ...] |
This is semantically identical (element types are unknown to PyO3) but passes mypy --strict. Verified that the parametrized form is --strict-clean:
from typing import Any
def make_list() -> list[Any]: ...
def take_dict(_x: dict[Any, Any]) -> None: ...
def make_tuple() -> tuple[Any, ...]: ...
# -> Success: no issues found
Notes
- Applies to both
Bound<'_, PyX>andPy<PyX>— they share the sameINPUT_TYPE/OUTPUT_TYPE. The repro above usesBound; thePy<...>forms produce the identical bare generics. stubtestis indifferent to the parametrization (the runtime objects are justlist/dict/tuple), so the change is safe there — this is purely about--strictcleanliness.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the src/lib.rs reproduction and the pyo3-introspection path used by module_stub_files for PyList, PyDict, and PyTuple. Run mypy --strict on the generated stub, then verify that both Bound and Py forms emit list[Any], dict[Any, Any], and tuple[Any, ...] and produce no strict-mode errors.
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
- Clearly specified
- Newbie friendliness
- 74/100