Skip to content

python API

If you want to call pyo3-stubgen from within python, you can ...

pyo3_stubgen

pyo3-stubgen generates .pyi typing files for extension modules.

It is designed to work for extension modules created in rust with pyo3 but should work with any compiled extension modules which include a __text_signature__ and optionally a __doc__ attribute for functions.

The package containing the module to be analysed must be installed in the current virtual environment, but does not need to be imported before running pyo3_stubgen.

Despite flake8's recommendation to the contrary, pyo3_stubgen adds docstrings to the .pyi files so that IDEs can provide them in hover pop-ups.

You will need to manually add the typing information to the generated files as this is not included in any of the function attributes available and is just as dependent upon the semantics of your functions as on the technical implementation.

Currently pyo3_stubgen only generates info for functions. Classes are on the to-do list.

genentry

genentry(function: FunctionType) -> str

Generate the signature and docstring information for a given function.

PARAMETER DESCRIPTION
function

the function to generate.

TYPE: FunctionType

Note
  • function must provide function.__text_signature__
  • If function.__doc__ is present this will be used to generate a docstring hint
RETURNS DESCRIPTION
str

A string suitable for inclusion in a .pyi file

Source code in pyo3_stubgen/generate.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def genentry(function: FunctionType) -> str:
    """
    Generate the signature and docstring information for a given function.

    Arguments:
      function: the function to generate.

    Note:
      - function _must_ provide `function.__text_signature__`
      - If `function.__doc__` is present this will be used to generate a docstring hint

    Returns:
      A string suitable for inclusion in a `.pyi` file
    """
    if function.__doc__:
        if "\n" in function.__doc__:
            doc = f'    """\n{textwrap.indent(function.__doc__,"    ")}\n    """'
        else:
            doc = f'    """{function.__doc__}"""'
    else:
        doc = '    ...'  # noqa: Q000
    return f"def {function.__name__}{function.__text_signature__}:\n{doc}\n"

genfile

genfile(modulename: str, outputlocation: Path) -> None

Generate a .pyi file for modulename and store it under the project root outputlocation.

PARAMETER DESCRIPTION
modulename

The fully qualified module name: e.g. pypkg.rustlib.

TYPE: str

outputlocation

The Path to the project root where the resulting file should be saved. Note:

TYPE: Path

Example

genfile("pypkg.rustlib", Path("python")) will result in the creation of ./python/pypkg/rustlib.pyi

Note
  • the package containing modulename must be installed and available for import such as from pypkg.rustlib import ... but does NOT have to be imported already.
  • the output file will be stored in a subdirectory based upon the fully qualified module name.
Source code in pyo3_stubgen/generate.py
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def genfile(modulename: str, outputlocation: Path) -> None:
    """
    Generate a `.pyi` file for `modulename` and store it under the project root `outputlocation`.

    Arguments:
      modulename: The _fully qualified_ module name: e.g. `pypkg.rustlib`.
      outputlocation: The `Path` to the _project root_ where the resulting file should be saved. Note: 

    Example:
      `genfile("pypkg.rustlib", Path("python"))` will result in the creation of `./python/pypkg/rustlib.pyi`

    Note:
      - the package containing modulename must be installed and available for import such as
      `from pypkg.rustlib import ...` but does NOT have to be imported already.
      - the output file will be stored in a subdirectory based upon the fully qualified module name.
    """
    module = import_module(modulename)
    output = genpyi(module)
    outputfile = outputlocation.joinpath("/".join(modulename.split("."))).with_suffix(".pyi")
    outputfile.parent.mkdir(parents=True, exist_ok=True)
    outputfile.write_text(output)

genpyi

genpyi(module: ModuleType) -> str

Generate the contents of a .pyi file for a given module.

PARAMETER DESCRIPTION
module

the module to generate

TYPE: ModuleType

Returns: A string suitable for use as a .pyi file, with the following caveats:

  • Return contents are prefixed with # flake8: noqa: PYI021. Flake8 believes that "Stub files should omit docstrings, as they're intended to provide type hints, rather than documentation". We believe that having docstring hints in IDE is really useful and linters get this info from the .pyi file, so this is a good thing to do.
  • No type information is usually provided in the __text_signature__ so you will need to add this manually to the .pyi file afterwards.
Source code in pyo3_stubgen/generate.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
def genpyi(module: ModuleType) -> str:
    """
    Generate the contents of a `.pyi` file for a given module.

    Arguments:
      module: the module to generate

    Returns: A string suitable for use as a `.pyi` file, with the following caveats: 

    - Return contents are prefixed with `# flake8: noqa: PYI021`. Flake8 believes that
    "Stub files should omit docstrings, as they're intended to provide type hints, rather than documentation".
    We believe that having docstring hints in IDE is _really useful_ and linters get this info from the `.pyi` file,
    so this is a good thing to do.
    - _No type information_ is usually provided in the `__text_signature__` so you will need to add this manually 
    to the `.pyi` file afterwards.
    """
    functions = [getattr(module,function) for function in dir(module)]
    definitions = [genentry(function) for function in functions if type(function) == BuiltinFunctionType]
    contents = ["# flake8: noqa: PYI021", *sorted(definitions)]
    return "\n".join(contents)