Type stub generation (*.pyi
files) and introspection
This feature is still in active development. See the related issue.
For documentation on type stubs and how to use them with stable PyO3, refer to this page
PyO3 has a work in progress support to generate type stub files.
It works using:
- PyO3 macros (
#[pyclass]
) that generate constant JSON strings that are then included in the built binaries by rustc if theexperimental-inspect
feature is enabled. - The
pyo3-introspection
crate that can parse the generated binaries, extract the JSON strings and build stub files from it. - [Not done yet] Build tools like
maturin
exposingpyo3-introspection
features in their CLI API.
For example, the following Rust code
#[pymodule]
pub mod example {
use pyo3::prelude::*;
#[pymodule_export]
pub const CONSTANT: &str = "FOO";
#[pyclass(eq)]
#[derive(Eq)]
struct Class {
value: usize
}
#[pymethods]
impl Class {
#[new]
fn new(value: usize) -> Self {
Self { value }
}
#[getter]
fn value(&self) -> usize {
self.value
}
}
#[pyfunction]
#[pyo3(signature = (arg: "list[int]") -> "list[int]")]
fn list_of_int_identity(arg: Bound<'_, PyAny>) -> Bound<'_, PyAny> {
arg
}
}
will generate the following stub file:
import typing
CONSTANT: typing.Final = "FOO"
class Class:
def __init__(self, value: int) -> None: ...
@property
def value(self) -> int: ...
def __eq__(self, other: Class) -> bool: ...
def __ne__(self, other: Class) -> bool: ...
def list_of_int_identity(arg: list[int]) -> list[int]: ...
The only piece of added syntax is that the #[pyo3(signature = ...)]
attribute
can now contain type annotations like #[pyo3(signature = (arg: "list[int]") -> "list[int]")]
(note the ""
around type annotations).
This is useful when PyO3 is not able to derive proper type annotations by itself.
Constraints and limitations
- The
experimental-inspect
feature is required to generate the introspection fragments. - Lots of features are not implemented yet. See the related issue for a list of them.
- Introspection only works with Python modules declared with an inline Rust module. Modules declared using a function are not supported.
FromPyObject::INPUT_TYPE
andIntoPyObject::OUTPUT_TYPE
must be implemented for PyO3 to get the proper input/output type annotations to use.- Because
FromPyObject::INPUT_TYPE
andIntoPyObject::OUTPUT_TYPE
areconst
it is not possible to build yet smart generic annotations for containers likeconcat!("list[", T::OUTPUT_TYPE, "]")
. See this tracking issue. - PyO3 is not able to introspect the content of
#[pymodule]
and#[pymodule_init]
functions. If they are present, the module is tagged as incomplete using a fakedef __getattr__(name: str) -> Incomplete: ...
function following best practices.