# Type stub generation (`*.pyi` files) and introspection

*This feature is still in active development.*
*See [the related issue](https://github.com/PyO3/pyo3/issues/5137).*

*For documentation on type stubs and how to use them with stable PyO3, refer to [this page](python-typing-hints.md)*

PyO3 has a work in progress support to generate [type stub files](https://typing.python.org/en/latest/spec/distributing.html#stub-files).

It works using:

1. PyO3 macros (`#[pyclass]`) that generate constant JSON strings that are then included in the built binaries by rustc if the `experimental-inspect` feature is enabled.
2. The `pyo3-introspection` crate that can parse the generated binaries, extract the JSON strings and build stub files from it.
3. Build tools like `maturin` exposing options in their CLI API to generate the stubs file.

For example, the following Rust code

```rust
#[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:

```python
import typing

CONSTANT: typing.Final = "FOO"


class Class:
    def __init__(self, value: int) -> None: ...

    @property
    def value(self) -> int: ...

    def __eq__(self, value: object, /) -> bool: ...
    def __ne__(self, value: object, /) -> bool: ...


def list_of_int_identity(arg: "list[int]") -> "list[int]": ...
```

The only piece of new syntax is that the `#[pyo3(signature = ...)]` attribute can 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.

To generate stubs file with `maturin` you can use `maturin generate-stubs --output stubs` that will build the project then generate the stubs in the `stubs` directory.
You can also directly integrate the stubs in the built wheels by doing `maturin build --generate-stubs` (works also with `maturin develop`).

PyO3 also provides the smaller `pyo3-introspection` binary that allows to generate stubs from an existing built extension using something like `pyo3-introspection my_module_binary.so my_module_name output` to introspect the `my_module_binary.so` dynamic library for the `my_module_name` Python module and generate its stubs in the `output` directory.

## 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](https://github.com/PyO3/pyo3/issues/5137) 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` and `IntoPyObject::OUTPUT_TYPE` must be implemented for PyO3 to get the proper input/output type annotations to use.
- 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 fake `def __getattr__(name: str) -> Incomplete: ...` function [following best practices](https://typing.python.org/en/latest/guides/writing_stubs.html#incomplete-stubs).
