stubpy.generator

stubpy.generator

Top-level orchestrator for stub generation — single files and entire packages.

Public functions

generate_stub pipeline

  1. Load — import the source file as a live module (skipped in AST_ONLY mode; graceful fallback in AUTO mode).

  2. AST pre-pass — harvest structural metadata without executing code.

  3. Scan imports — build a {name: stmt} map for the source file.

  4. Build alias registry — discover type-alias sub-modules.

  5. Build symbol table — merge AST + runtime data into a SymbolTable.

  6. Emit stubs — generate stubs for every public symbol in source order: aliases (TypeVar / TypeAlias), classes, overloaded functions, plain functions, and module-level variables. __all__ filtering is applied via the symbol table.

  7. Assemble header — collect typing names, type-module imports, special imports (abc, dataclasses), and cross-file imports.

  8. Write — write the complete .pyi to output_path.

generate_package calls generate_stub for every .py file found under the package root, mirroring the directory tree under the output directory.

Single-file generation

generate_stub(filepath: str, output_path: str | None = None, ctx: StubContext | None = None) str[source]

Generate a .pyi stub file for the Python source at filepath.

A fresh StubContext is created when ctx is None, making this function fully re-entrant. Pass an explicit ctx to supply custom StubConfig options (e.g. include_private=True, execution_mode=ExecutionMode.AST_ONLY) or to inspect diagnostics after the call.

Execution modes

RUNTIME (default)

Execute the module; full introspection available.

AST_ONLY

Parse the AST only — no module execution. Safer for modules with import-time side effects; live types will be None.

AUTO

Execute when possible; fall back to AST-only on load failure.

param filepath:

Path to the .py source file.

type filepath:

str

param output_path:

Where to write the .pyi file. Defaults to the same directory and stem as filepath with a .pyi extension.

type output_path:

str, optional

param ctx:

Pre-configured context. Created fresh when None.

type ctx:

StubContext, optional

returns:

str – Full stub content as a string, identical to what is written to disk.

raises FileNotFoundError:

If filepath does not exist.

raises ImportError:

If the source file cannot be loaded as a module (RUNTIME mode only; AUTO mode falls back to AST-only instead of raising).

See also

generate_package

Batch generation for a whole package directory.

stubpy.loader.load_module

Stage 1 — module loading.

stubpy.ast_pass.ast_harvest

Stage 2 — AST pre-pass.

stubpy.symbols.build_symbol_table

Stage 5 — symbol table.

stubpy.emitter.generate_class_stub

Class stub emission.

stubpy.emitter.generate_function_stub

Function stub emission.

stubpy.emitter.generate_variable_stub

Variable stub emission.

stubpy.emitter.generate_alias_stub

Alias/TypeVar stub emission.

stubpy.emitter.generate_overload_group_stub

Overload group stub emission.

collect_classes(module: ModuleType, module_name: str) list[type][source]

Return all classes defined in module, sorted by source-line order.

Uses inspect.getmembers() filtered to classes whose __module__ matches module_name, so only classes defined in the file itself are included — not classes imported into it.

Parameters:
Returns:

list of type – Classes sorted by their first source line, mirroring source order.

Package generation

generate_package(package_dir: str | Path, output_dir: str | Path | None = None, ctx_factory: Callable[[Path, Path], StubContext] | Callable[[], StubContext] | None = None, config: StubConfig | None = None) PackageResult[source]

Generate .pyi stubs for every .py file in package_dir.

Walks package_dir recursively and calls generate_stub() for each .py source file. For every sub-directory that contains an __init__.py, the corresponding __init__.pyi is created under output_dir (if it was not already produced by generate_stub).

Files matching any pattern in config.exclude are skipped. Files that fail with an exception or ERROR-level diagnostics are recorded in PackageResult.failed and processing continues.

Parameters:
  • package_dir (str or Path) – Root of the package to process.

  • output_dir (str or Path or None) – Directory where stubs are written. The subdirectory structure of package_dir is reproduced under output_dir. When None (default), stubs are written alongside the source files.

  • ctx_factory (callable or None) –

    Called to produce a fresh StubContext for each file. Two signatures are accepted:

    • ctx_factory() — called with no arguments (backward compatible).

    • ctx_factory(source_path, output_path) — called with the absolute Path of the source .py file and the destination .pyi path, allowing per-file customisation (e.g. different execution_mode for slow modules, extra exclude patterns for generated files, custom annotation handlers).

    When None, a context derived from config (or a default config) is used.

  • config (StubConfig or None) – Configuration applied when ctx_factory is None. When both are None, StubConfig defaults are used.

Returns:

PackageResult – Contains stubs_written (success paths) and failed ((path, diagnostics) pairs for errored files).

Raises:

FileNotFoundError – If package_dir does not exist on disk.

Examples

>>> from stubpy import generate_package
>>> result = generate_package("mypackage/", "stubs/")
>>> print(result.summary())
Generated 8 stubs, 0 failed.
class PackageResult(stubs_written: list[Path] = <factory>, failed: list[tuple[~pathlib.Path, list[~stubpy.diagnostics.Diagnostic]]]=<factory>)[source]

Bases: object

Outcome of a generate_package() run.

stubs_written

Absolute paths of every .pyi file successfully written.

Type:

list of Path

failed

One entry per source file that raised an exception or accumulated ERROR-level diagnostics. Each entry is (source_path, diagnostics).

Type:

list of tuple[Path, list[Diagnostic]]

Examples

>>> r = PackageResult()
>>> r.summary()
'Generated 0 stubs, 0 failed.'
stubs_written: list[Path]
failed: list[tuple[Path, list[Diagnostic]]]
summary() str[source]

Return a one-line human-readable summary.

Examples

>>> r = PackageResult(stubs_written=[Path("a.pyi")], failed=[])
>>> r.summary()
'Generated 1 stub, 0 failed.'
__init__(stubs_written: list[Path] = <factory>, failed: list[tuple[~pathlib.Path, list[~stubpy.diagnostics.Diagnostic]]]=<factory>) None

Pipeline stages

Each call to generate_stub() runs eight stages in order:

generate_stub(filepath)
    │
    ├─ 1. loader      load_module()                → module, path, name
    │        └─ (skipped in AST_ONLY; warning+fallback in AUTO)
    ├─ 2. ast_pass    ast_harvest()                → ASTSymbols
    ├─ 3. imports     scan_import_statements()     → import_map
    ├─ 4. aliases     build_alias_registry()       → ctx populated
    ├─ 5. symbols     build_symbol_table()         → SymbolTable
    ├─ 6. emitter     for each symbol (source order):
    │       ├─ AliasSymbol    → generate_alias_stub()
    │       ├─ ClassSymbol    → generate_class_stub()
    │       │       └─ for each method:
    │       │           resolver  resolve_params()
    │       │           emitter   generate_method_stub()
    │       ├─ OverloadGroup → generate_overload_group_stub()
    │       ├─ FunctionSymbol → generate_function_stub()
    │       └─ VariableSymbol → generate_variable_stub()
    ├─ 7. imports     collect_typing_imports()     → header
    │                 collect_special_imports()
    │                 collect_cross_imports()
    └─ 8. write       .pyi file written to disk

Execution modes

The pipeline respects ExecutionMode:

RUNTIME (default)

Execute the module at stage 1. All introspection paths available.

AST_ONLY

Skip stage 1 entirely. Live types will be None; stubs are built from AST metadata only. Useful for modules with import-time side effects.

AUTO

Attempt stage 1; if the load raises any exception, record a WARNING diagnostic and continue with AST-only data.

Package processing

generate_package() calls generate_stub() for every .py file found by a recursive directory walk. It mirrors the source tree under the output directory and ensures every sub-package has an __init__.pyi. Files that fail are collected in PackageResult.failed rather than aborting the run.