Changelog¶
All notable changes to stubpy are recorded here. The format follows Keep a Changelog.
0.6.0¶
Added
Mixed method ↔ function forwarding chains —
**kwargsand*argsare now resolved across arbitrary mixed chains: method → function → method, function → class constructor → method, and any depth thereof.resolve_params()andresolve_function_params()now call each other when a forwarding target crosses the class/module boundary. A shared_seenfrozenset prevents infinite recursion in mutually-recursive patterns.Property MRO tracking (GAP-14 closed) — when a subclass redefines only the getter of a property whose setter lives in a parent class (or vice-versa), the generated stub now emits both
@propertyand@name.setterby walking the full MRO via the new_find_property_mro()helper.Incremental stub merge (GAP-15 closed) — new
stubpy.stub_mergemodule. Settingincremental_update = trueinstubpy.toml(or passing--incrementalon the CLI) wraps generated content in# stubpy: auto-generated begin/endmarkers and merges only the marked region on subsequent runs, leaving manually edited content outside the markers untouched. Marker matching is case-insensitive and whitespace- lenient. Multiple marker pairs per file and half-open pairs are handled gracefully.Docstring type inference (GAP-11 partial, closed) — new
stubpy.docstringmodule with parsers for NumPy, Google, and Sphinx/reST docstring conventions. Wheninfer_types = trueis set (or--infer-typeson the CLI), parameters and return types inferred from docstrings are emitted as# type: Xinline comments — visually distinct from real annotations. All three parsers run and their results are merged, so mixed-style docstrings receive full coverage. Indented docstrings (the common case) are parsed correctly.``ctx_factory`` file-info support in
generate_package()— the factory callable now accepts either()or(source_path, output_path)signatures. This lets callers customise theStubContextper-file (e.g. useAST_ONLYfor slow-importing modules, attach custom annotation handlers for specific subpackages, or set different output styles).``@typing.type_check_only`` support — classes decorated with
@type_check_onlynow emit the@type_check_onlydecorator in the stub, correctly signalling to type checkers that the class is absent at runtime.``@typing.dataclass_transform`` support — factory classes decorated with
@dataclass_transformnow emit the decorator with its parameters in the stub (PEP 681).CLI flags —
--infer-typesenables docstring type inference;--incrementalenables the stub-merge mode;--exclude PATTERNskips files matching a glob pattern during package processing (repeatable for multiple patterns, appended to any config-fileexcludelist);--no-respect-allstubs all symbols regardless of__all__.TOML config keys —
infer_types(alias:infer_types_from_docstrings) andincremental(alias:incremental_update) are now recognised instubpy.toml/[tool.stubpy].respect_allwas already supported but is now also fully documented and exposed via--no-respect-allon the CLI.``StubConfig`` fields —
infer_types_from_docstrings: bool(defaultFalse) andincremental_update: bool(defaultFalse).Dynamic version —
pyproject.tomlnow usesdynamic = ["version"]sourced fromstubpy.__version__. Bumping the version in__init__.pyautomatically propagates to the package metadata.Python 3.14 CI — the GitHub Actions test matrix now includes Python 3.14 (pre-release,
allow-prereleases: true) on all three OS targets.New demo module —
demo/dispatch.pyexercises method → function chains, property MRO inheritance, and docstring-only types.Test restructure — the
tests/directory now mirrorsstubpy/’s module layout. Previously scattered files (test_function_resolver.py,test_special_classes.py,test_module_symbols.py,test_property_mro.py,test_mixed_chains.py) were consolidated intotest_resolver.py,test_emitter.py, and newtest_generator.py,test_main.py,test_docstring.py, andtest_stub_merge.py. Shared helpers and fixtures moved toconftest.py.
Fixed
f-string syntax in
annotations.py(line 388) was invalid on Python 3.10 and 3.11 (nested quotes inside f-strings require Python 3.12+). Fixed by extracting", ".join(parts)to an intermediate variable.Indented Google-style docstrings were not parsed (section headers like `` Args:`` with leading spaces were silently skipped). The parser now detects the base indentation level of the docstring body and matches section headers relative to it.
Comma placement in multi-line stubs with inline comments — the new
_join_params_multilinehelper ensures the trailing comma appears before any# type:comment, producing syntactically valid stubs.Signature validity after namespace resolution —
_enforce_signature_validityis now also applied in the MRO walk path, preventing invalid “non-default parameter follows default” errors when namespace-resolved parameters are absorbed.
Docs
API reference cleaned up: duplicate “Full API reference” section removed, empty
AST pre-pass/Symbol table/Emitterssub-sections replaced with substantive content and cross-links.New API pages for
stubpy.docstringandstubpy.stub_merge.
Known limitations (documented)
Positionally-bound kwargs targets — when a method forwards
**kwargsto a function viaf(self.x, y, **kwargs), the resolver cannot detect thatself.xpositionally fills the first parameter of f. All of f’s non-variadic parameters (including the positionally-bound ones) appear in the generated stub. Workaround: pass the pre-bound argument by keyword (f(x=self.x, **kwargs)) or use explicit named parameters instead of**kwargs.Stub markers are file-level for
generate_stub— theincremental_update/--incrementalflag wraps the entire generated stub. Placing# stubpy: auto-generated begin/endmarkers inside class bodies is supported by the low-levelmerge_stubs()API but not by thegenerate_stubpipeline (which would inject a full file stub into the class body).
0.5.3¶
Added
``–union-style`` flag (renamed from
--typing-style) — controls whether union annotations are emitted asX | None(modern, PEP 604, the default) orOptional[X](legacy). The rename makes the flag’s scope unambiguous alongside--alias-style.``–include-docstrings`` / ``include_docstrings`` — when enabled, each function, method, and class stub receives the original docstring as a triple-quoted body instead of
.... Useful when stubs double as quick-reference documentation for IDEs.``register_annotation_handler(predicate)`` — public extension hook that appends a custom
(annotation, ctx) → strhandler to the dispatch table. Allows third-party libraries (Pydantic, attrs, beartype, …) to teach stubpy how to render their custom annotation types without forking the source. Exported from the top-levelstubpypackage.Glob expansion in the CLI — path arguments containing
*,?, or[are expanded by Python’sglob.glob()(recursive=True), sostubpy "src/*.py"andstubpy "**/*.py"work even when the shell does not expand the pattern. Explicit paths without wildcards are unchanged. All combinations of files, directories, and glob patterns may be mixed in one invocation.``TypedDict`` stub generation — classes created with
TypedDict()are now emitted as cleanclass Name(TypedDict):/class Name(TypedDict, total=False):blocks with per-field annotations, instead of falling through to the generic class path.Enum stub generation —
EnumandIntEnumsubclasses are emitted with the correct base class (Enum,IntEnum, etc.) andfrom enum import …is injected automatically. Internal implementation methods (_generate_next_value_,_missing_, …) are suppressed from the stub.Enum-valued defaults rendered correctly —
default_to_strnow emitsClassName.MEMBER_NAMEfor Enum member defaults (e.g.BlendMode.NORMAL) instead of the non-valid<BlendMode.NORMAL: 'normal'>repr. Type objects used as defaults are rendered as their__name__.NamedTuple extra methods —
@propertydescriptors and ordinary methods defined on a NamedTuple subclass are now emitted in the stub. Auto-generated NamedTuple internals (_make,_asdict,_replace,__getnewargs__) are suppressed.Python 3.10 compatibility fixes in annotations:
_UnionTypeguard — thetypes.UnionTypecheck is wrapped ingetattrso the annotations module imports without error on Python < 3.10 whereUnionTypedoes not exist.types.GenericAliasis now an explicit predicate in the dispatch table, so PEP 585 built-in subscripts (list[int],tuple[str, ...]) are always matched correctly before the generic__origin__catch-all.typing.TypeVarTupletest skipped on Python < 3.11 where it is absent.
Expanded demo — the demo package is now a coherent PixelForge graphics library with realistic module names:
demo/primitives.py— dataclass, NamedTuple, TypedDict, Enum, ABC +**kwargsMRO backtracing throughShape → Circle / Rect / Text.demo/scene.py— TypeVar, Generic[T], Generic[K,V], Protocol, TypeAlias, NewType, bound / constrained TypeVars.demo/style.py— three-variant@overload, generic overload, overloaded classmethod, GradientStop NamedTuple.demo/export.py— cross-file imports, TYPE_CHECKING guard, async export, typed*args.
CI: Python 3.14-dev — the test matrix now includes a Python 3.14 pre-release build on Ubuntu (
allow-prereleases: true). A separatecoveragejob uploads to Codecov; adocsjob builds the HTML documentation and deploys to GitHub Pages on every push tomain.
Fixed
_generate_namedtuple_stubwas usingrepr()for field defaults, which produced broken stubs when a default contained quotes or was an Enum member. Now usesdefault_to_str().collect_special_importsdid not detectEnum/IntEnum/StrEnumbase-class references in the stub body. Afrom enum import …line is now injected automatically when any Enum subclass is emitted.__main__.pyrefactored into clearly-separated helper functions (_build_parser,_expand_paths,_build_config,_run_file,_run_package,_run_multi) with no module-level side effects;globmoved to a module-level import.Dead
all_diagnosticslist in_run_package(collected but never printed) removed.
0.5.2¶
Added
Function-level ``**kwargs`` / ``*args`` backtracing.
resolve_function_params()expands variadic parameters for module-level functions using AST-detected forwarding targets, exactly asresolve_params()does for class methods via the MRO.Two new fields on
FunctionInforecord where variadics are forwarded:kwargs_forwarded_toandargs_forwarded_to. These are populated by a new body scan inside_harvest_function()— no extra source parse at emission time.All parameter kinds are handled:
/(positional-only) — promoted toPOSITIONAL_OR_KEYWORDwhen absorbed via**kwargs(they can only be passed by keyword through the forwarding interface).*args— preserved when unresolved or explicitly typed.Keyword-only (after
*or*args) — merged and emitted with the bare*separator.Residual
**kwargs— kept only when the forwarding target itself still has**kwargs(the chain is still open).Chained forwarding (
A → B → C) — resolved recursively, with cycle detection to prevent infinite recursion.
Example:
# source def make_color(r: float, g: float, b: float, a: float = 1.0) -> Color: ... def make_red(r: float = 1.0, **kwargs) -> Color: return make_color(r=r, **kwargs) # generated stub — previously **kwargs was left unexpanded def make_red(r: float = 1.0, *, g: float, b: float, a: float = 1.0) -> Color: ...
Default-ordering enforcement. When absorbed parameters would violate Python’s rule that non-default parameters may not follow defaulted ones in the positional portion of a signature, stubpy automatically promotes the offending parameters to
KEYWORD_ONLY(after a bare*). The new helper_enforce_signature_validity()handles this for both the function resolver and the class-method MRO resolver.Shared resolver infrastructure. Three new helpers used by both resolvers eliminate previously duplicated logic:
_merge_concrete_params(),_finalise_variadics(), and_enforce_signature_validity().``StubContext.module_namespace`` field. The live module’s
__dict__is stored onStubContextafter stage 1, making it accessible to downstream extension code.Multi-file CLI. The
stubpycommand now accepts multiple paths:stubpy a.py b.py c.py stubpy src/*.py stubpy module.py mypackage/
Paths may be any mix of
.pyfiles and package directories. When more than one path is given,-ois silently ignored (a warning is printed to stderr); stubs are written alongside each source file.64 new tests in
tests/test_function_resolver.pycovering function-level resolution, AST body scanning, all parameter kinds, chained and recursive forwarding, cycle detection, default-ordering enforcement,*//separator placement, multi-file CLI, and full demo-package integration.Expanded demo —
demo/functions.pynow exercises positional-only parameters (/), chained**kwargsforwarding, typed*args, combined*args+**kwargsforwarding, and keyword-only parameters after*.
Fixed
SyntaxWarning: invalid escape sequence '\('in the_extract_locally_defined_namesdocstring instubpy/imports.py.Duplicate-description Sphinx warnings eliminated.
docs/api/public.rsthas been rewritten as a pure navigation / summary page (autosummarytables and cross-references only, zeroautofunction/autoclassdirectives). All full API documentation lives in the per-module pages.:no-index:annotations removed from per-module pages now that they are the sole canonical source.Duplicate ``changelog`` label Sphinx warning. The explicit
.. _changelog:label inchangelog.rstwas removed — Sphinx generates achangeloganchor automatically from the toctree entry filename, making the hand-written label redundant.RST formatting error in
docs/examples/project_integration.rst: a section heading beginning with**kwargswas treated as an unclosed bold-emphasis node. Rephrased using the inline-code form``**kwargs`to avoid the ambiguity.
0.5.1¶
Added
``# stubpy: ignore`` directive. Place
# stubpy: ignore(case-insensitive) at the top of any.pyfile (before any code) to exclude it from stub generation entirely. The generator writes a minimalfrom __future__ import annotationsstub and records anINFOdiagnostic. Useful for generated files, C extensions, or modules that are intentionally un-stubbed.Implicit TypeAlias detection for bare assignments without an explicit
TypeAliasannotation. Three patterns are now promoted toTypeVarInfoentries during the AST pre-pass:PEP 604 union RHS —
Number = int | floatSubscripted generic RHS —
Length = Union[str, float, int],Items = list[int]Known built-in or typing type name —
MyStr = str,Count = int,MyList = list
SomeArbitraryClass = OtherClassis intentionally NOT promoted (cannot determine at parse time whetherOtherClassis a type or a value).Python 3.12+ PEP 695 ``type`` statement support. The AST harvester now recognises
type Vector = list[float]andtype Stack[T] = list[T]via a newvisit_TypeAliasvisitor method. These are stored asTypeVarInfowithkind="TypeAlias".``alias_style`` configuration option in
StubConfig. Controls the output format for TypeAlias declarations:"compatible"(default) —Name: TypeAlias = <rhs>(Python 3.10+)"pep695"—type Name = <rhs>(Python 3.12+ only)"auto"— selectspep695on Python 3.12+, otherwisecompatible
Available via
stubpy.toml/pyproject.tomland the new--alias-styleCLI flag.Compact variable/alias block spacing. Consecutive single-line stubs of the same kind (variables or type aliases) are now grouped without blank lines between them, matching the style of hand-written stubs. A blank line still separates different symbol kinds (variable block → class, etc.).
``–alias-style`` CLI flag —
compatible,pep695, orauto.``ASTSymbols.skip_file`` field —
Truewhen the# stubpy: ignoredirective is found; read by the generator to skip emission.
Fixed
``variables.pyi`` missing ``from demo import types`` and equivalent variable-only files.
collect_cross_importsnow detects lowercase dotted references (types.Length) in addition to capitalised annotation names.False-positive typing imports —
container.pyiwas incorrectly importingContainerfromtyping;graphics.pyiimportedText;element.pyiimportedoverride. All were user-defined names in the same stub body.collect_typing_imports()now excludes names that are locally defined (classes, functions, parameter names) in the stub body.Duplicate ``from demo import types`` in stubs where the same import was detected by both the alias-registry path and the new dotted-reference path. Stage 7 (header assembly) now uses an ordered-insertion deduplication set so any import statement can appear at most once, regardless of detection path.
``_emit_class`` NameError causing empty stub bodies. A bad str_replace in a previous edit accidentally embedded the
_emit_classfunction body inside an unreachable path afterreturnin_join_sections. Restored as a standalone function.Phase reference (“Phase 4 additions”) removed from
emitter.pymodule docstring.
Changed
collect_cross_imports()now performs two detection passes: capitalised annotation names (existing) and lowercase dotted module references (new). Both passes share a single deduplication set.demo/types.pyupdated to use explicitTypeAliasannotations (Number: TypeAlias = int | float, etc.) for unambiguous stub output.Copyright year updated to 2026.
0.5.0¶
Added
Package batch generation (
generate_package()). Recursively stubs every.pyfile in a directory tree, mirrors the structure under an output directory, and creates__init__.pyimarkers for every sub-package. Files that fail are collected inPackageResultrather than aborting the run.generate_packagelives instubpy.generatoralongsidegenerate_stub— both functions share the same concern and the same module.Configuration file support (
stubpy.config). stubpy now searches upward from the target path for astubpy.tomlor a[tool.stubpy]section inpyproject.toml. On Python 3.11+ the stdlibtomllibis used; on Python 3.10 thetomlibackport is tried with a minimal hand-rolled fallback for the simple key/value syntax stubpy needs. Config file values are overridden by CLI flags.``union_style`` configuration option in
StubConfig."modern"(default) emits PEP 604X | Nonesyntax;"legacy"emitsOptional[X]/Union[X, Y]for compatibility with older type checkers. Applies to both the PEP 604UnionTypehandler and thetyping.Unionbranch of the generic handler.``exclude`` and ``output_dir`` fields on
StubConfig.excludeis a list of glob patterns (matched against relative POSIX paths) for files to skip during package processing.output_diris the default output root forgenerate_packagewhen none is specified on the CLI.New CLI flags:
--execution-mode(runtime/ast_only/auto),--union-style(modern/legacy), and--no-config(skip config-file lookup). Thepathpositional argument now accepts either a.pyfile or a directory; a directory triggers package mode.``PackageResult`` dataclass (in
stubpy.generator) withstubs_written,failed, andsummary()members.
Changed
"modern"is now the defaultunion_style. Stubs generated without explicit configuration now emitstr | Noneinstead ofOptional[str]. Tests that asserted the oldOptional[str]form have been updated; callers that need the legacy form should setStubConfig(union_style="legacy").generate_stub()gained aFileNotFoundErrorguard at the top of the function (before any I/O) so the error is always recorded in the diagnostic collector before being re-raised.
Fixed
StubContextattributes no longer produce Sphinxduplicate object descriptionwarnings.context.rstnow uses:no-index:onautoclassdirectives and:exclude-members:onStubContextto prevent duplication.
0.4.0¶
Added
TypeVar / TypeAlias / NewType / ParamSpec / TypeVarTuple re-emission. Module-level declarations of these forms are now preserved in the generated stub verbatim from the AST pre-pass. Previously they were silently dropped. A new
generate_alias_stub()function handles emission for all alias-like symbols.Generic base class preservation (
Generic[T],Generic[K, V], etc.).generate_class_stub()now reads__orig_bases__(PEP 560) in preference to__bases__. This preserves subscript information that__bases__erases —Generic[T]was previously collapsed to justGeneric.TypeVar / ParamSpec / TypeVarTuple annotation rendering. A new dispatch handler in
stubpy.annotationsconvertsTypeVar,ParamSpec, andTypeVarTupleobjects to their bare name (e.g.T). Python 3.12+ renders these objects as~Tviastr(); the new handler is consistent across Python 3.10–3.13.@overload stubs.
@overload-decorated module-level functions are now collected as anOverloadGroupand emitted with one@overloadstub per variant viagenerate_overload_group_stub(). The concrete implementation stub is suppressed per PEP 484 convention.Positional-only ``/`` separator (PEP 570).
insert_pos_separator()inserts a bare/sentinel after the lastPOSITIONAL_ONLYparameter. Bothgenerate_method_stub()andgenerate_function_stub()now emit/where required.Positional-only parameter normalisation in MRO backtracing. When a parent method’s
POSITIONAL_ONLYparameters are absorbed by a child’s**kwargs, the resolver now promotes them toPOSITIONAL_OR_KEYWORD. Emitting them as positional-only in the child stub would have produced invalid Python (a misplaced/).``from module import *`` support in import scanner.
scan_import_statements()now records star-import statements under the reserved key"*"so callers can handle them explicitly rather than silently discarding them.Dynamic typing-import coverage.
collect_typing_imports()now scanstyping.__all__at import time instead of a hard-coded 14-name tuple. This automatically picks up names added in future Python releases. Matching uses whole-word\\bboundaries to avoid false positives (e.g.Listno longer matches insideBlackList).AST_ONLY and AUTO execution modes fully wired.
generate_stub()now correctly skips module execution inAST_ONLYmode and falls back gracefully to AST-only on load failure inAUTOmode. Previously these modes were defined but not fully implemented in the generator pipeline.New public emitter functions.
generate_alias_stub()andgenerate_overload_group_stub()are now exported fromstubpyand available as part of the extension API.
Fixed
build_alias_registry()raisedTypeErrorwhen called withmodule=None(e.g. inAST_ONLYmode). It now returns early without error.generate_stub()did not read source before the stage-1 load block, causingFileNotFoundErrorto bypass the diagnostic recorder. The path existence check is now done once up-front and raisesFileNotFoundErrorconsistently before any I/O.Pre-existing test
test_inline_import_not_duplicatedreferenced a non-existentdemo_module. It now usesExecutionMode.AUTOwith a sentinel module name to exercise the deduplication path without requiring a real importable module.
Changed
generate_stub()Stage 6 now dispatches togenerate_alias_stub()forAliasSymbolentries and togenerate_overload_group_stub()forOverloadGroupentries. The placeholder comment# AliasSymbol and OverloadGroup are handled in future workhas been removed.stubpy.importsmodule docstring updated to reflect dynamictyping.__all__scanning and star-import support.
0.3.1¶
Fixed
--include-privatehad no effect when the target module declared__all__. Private names were passing theinclude_privategate but then being incorrectly filtered out by the__all__check inbuild_symbol_table._include(). Private names are now controlled solely byinclude_privateand bypass__all__entirely, while__all__continues to restrict which public names are emitted.Stale contradicting assertion removed from
TestVariableHarvest.test_private_variable_skippedthat was left over from a bad merge (lines 199-201 correctly asserted all names are harvested; line 202 immediately contradicted them).
Added
demo/container.py—Containergainsget()andclone()methods;Layergainslock(),unlock(),hide(),show_layer()methods and alabelkeyword-only parameter.demo/element.py—Elementis now an abstract base class (class Element(ABC):) with@abstractmethodonrenderandbounding_box;Transform(NamedTuple)is exported.tests/test_integration.py—TestInlineImportsdocuments and tests inline-import (inside function / method bodies) discovery and re-emission behaviour.
Notes
Inline imports (imports placed inside function or method bodies to break circular dependencies) are fully supported.
scan_import_statementsusesast.walkacross the entire source file, so inline imports are discovered. An inline import is re-emitted in the.pyiheader when and only when the imported name actually appears in a stub annotation (return type, parameter type, base class, etc.).
0.3.0¶
Added
Module-level function stubs:
generate_stubnow emitsdefandasync defstubs for every top-level function, not just class methods. The same inline / multi-line formatting and**kwargsback-tracing used for class methods applies here too.Module-level variable stubs: annotated variables (
x: int = 1) emitname: Typestubs. Unannotated assignments fall back totype(value).__name__from the runtime value, with aWARNINGdiagnostic recorded.__all__filtering: when the target module declares__all__,generate_stub()includes only the named symbols. Applies to classes, functions, and variables uniformly. Filtering is handled once inbuild_symbol_table()rather than scattered across the pipeline.--include-privateCLI flag: includes symbols whose names start with_. Wired throughStubConfigandStubContext.async defdetection on class methods:generate_method_stub()now prefixes stubs withasyncwheninspect.iscoroutinefunction()orinspect.isasyncgenfunction()returnsTruefor the underlying callable. Applies to regular methods, classmethods, staticmethods, and async generators.@abstractmethodsupport: abstract callables (those with__isabstractmethod__ = True) emit@abstractmethodin their stub. Decorator stacking order is correct:@classmethod/@staticmethodfirst, then@abstractmethod. Abstract properties emit@abstractmethodbefore@property.@dataclasssupport: decorated classes emit the@dataclassdecorator line and a synthesised__init__built from__dataclass_fields__.ClassVarandinit=Falsefields are excluded from the signature;default_factoryfields are shown asfield: Type = .... Inherited field types are resolved through the MRO.__post_init__is included in_PUBLIC_DUNDERS.NamedTuplesupport: NamedTuple subclasses emitclass Name(NamedTuple):with per-field annotations and defaults. Auto-generated methods (_make,_asdict,_replace) are omitted.collect_special_imports(): scans the generated stub body for@abstractmethod,ABC, and@dataclassand returns the correspondingfrom abc import …/from dataclasses import …statements needed in the header.NamedTupleadded to_TYPING_CANDIDATESso it is auto-imported when present in the stub body.New
ctxparameter ongenerate_stub(): callers can pass a pre-configuredStubContext(e.g. with customStubConfig) instead of relying on the internal default.
Changed
The AST harvester (
ASTHarvester) is now a pure collector — it gathers all names, including private ones. Private-name filtering is handled exclusively bybuild_symbol_table()via theinclude_privateparameter. This is necessary for--include-privateto work correctly.build_symbol_table()gains aninclude_privateparameter (defaultFalse).Stub emission is now driven by
ctx.symbol_table.sorted_by_line()in a single loop, so classes, functions, and variables always appear in source-definition order regardless of their kind.__all__is read from the AST pre-pass with a runtimemodule.__all__fallback; it is no longer applied in the emitter but exclusively inbuild_symbol_table._SKIP_IMPORT_PREFIXESextended with"from dataclasses"so dataclasses imports are not incorrectly re-emitted as cross-module imports.Test suite expanded with two new pytest modules:
tests/test_module_symbols.pyandtests/test_special_classes.py.
0.2.0¶
Added
stubpy/diagnostics.py—DiagnosticCollectorreplaces baretry/except passblocks throughout the pipeline. Every stage recordsDiagnosticentries with aDiagnosticLevel(INFO/WARNING/ERROR) and aDiagnosticStageidentifying which pipeline stage raised the issue.stubpy/ast_pass.py—ast_harvest()performs a read-onlyast.NodeVisitorpass over the source before the module is executed, collecting top-level class definitions (with base-class and decorator lists), sync and async function definitions (with raw annotations), annotated variables,__all__, andTypeVar/TypeAlias/ParamSpec/TypeVarTuple/NewTypedeclarations. Results are stored inASTSymbols.stubpy/symbols.py—SymbolTablereplaces the ad-hoclist[type]previously used to track classes. Each entry is aStubSymbolsubclass:ClassSymbol— livetype+ AST metadataFunctionSymbol— callable + AST function node +is_asyncflagVariableSymbol— module-level variable with annotated or inferred typeAliasSymbol—TypeAlias/NewTypedeclarationOverloadGroup— multiple@overloadvariants sharing a name
--verboseCLI flag: print allINFO,WARNING, andERRORdiagnostics tostderrafter generation.--strictCLI flag: exit with code1if anyERROR-level diagnostic was recorded during the run, even when the stub file was written successfully.StubConfig— per-run configuration dataclass (execution_mode,include_private,respect_all,verbose,strict).ExecutionModeenum —RUNTIME/AST_ONLY/AUTOcontrols whether the target module is executed.StubContextgains four new fields:config,diagnostics,symbol_table,all_exports.load_module()gains an optionaldiagnosticsparameter; load errors are recorded in the collector before being re-raised.
Fixed
Ellipsissentinel (...) now renders as"..."in stubs.Type-alias preservation across
Optional/| Noneunions.Type-alias preservation in mixed-union parameters (
Union[types.Color, int]).from pkg import typesheader import was silently dropped when the raw-annotation override path was taken informat_param.✓checkmark in CLI output replaced with plain text to avoidUnicodeEncodeErroron Windows terminals.
Changed
Pipeline extended from 6 to 9 stages: AST pre-pass (stage 2) and symbol table assembly (stage 5) are now explicit steps inside
generate_stub.
0.1.1¶
Fixed
*argsordering bug in_resolve_via_mro: when a child class had both typed*argsand**kwargs,*argswas incorrectly placed after any already-appended**kwargs, producing invalid Python syntax.__qualname__replaced with__name__inannotation_to_strandgenerate_class_stub.Fixed duplicate autodoc warnings in Sphinx build.
Fixed
resolver.rstreStructuredText*argsemphasis warning.
Added
New edge-case tests in
tests/test_integration.py:TestStaticMethodsandTestArgsAndKwargsTogether.
Changed
Private symbols removed from public-facing API reference docs.
0.1.0¶
Initial release.
Added
generate_stub(filepath, output_path)— main public API.stubpyCLI with-o / --outputand--printflags.**kwargsbacktracing via full MRO walk.*argsbacktracing with explicit-annotation preservation.@classmethod cls(**kwargs)detection via AST.Type-alias preservation for imported type sub-modules.
Cross-file import re-emission in
.pyiheaders.Keyword-only
*separator inserted automatically.Inline formatting for ≤ 2 params; multi-line with trailing commas.
StubContextdataclass — fully re-entrant.Dispatch-table
annotation_to_str— extensible without editing a chain.Support for all common annotation forms.
Complete pytest test suite.
Sphinx documentation with Furo theme.