Overloads and TypeVar

stubpy correctly handles @overload decorated functions and generic TypeVar declarations.

@overload stubs

Per PEP 484, a stub should contain one @overload entry per variant and suppress the concrete implementation. stubpy does this automatically by grouping overloads detected during the AST pre-pass:

from typing import overload

@overload
def parse(value: str) -> str: ...
@overload
def parse(value: int) -> int: ...
def parse(value):
    return value   # concrete implementation

Generated stub — the concrete def parse(value) is suppressed:

@overload
def parse(value: str) -> str: ...

@overload
def parse(value: int) -> int: ...

Three-variant overload

@overload
def scale(v: int,   f: int)   -> int:   ...
@overload
def scale(v: float, f: float) -> float: ...
@overload
def scale(v: str,   f: int)   -> str:   ...
def scale(v, f): return v * f

Generated stub:

@overload
def scale(v: int, f: int) -> int: ...

@overload
def scale(v: float, f: float) -> float: ...

@overload
def scale(v: str, f: int) -> str: ...

Overloaded classmethod

class Converter:
    @classmethod
    @overload
    def from_str(cls, raw: str, *, radix: int) -> "Converter[int]": ...
    @classmethod
    @overload
    def from_str(cls, raw: str) -> "Converter[str]": ...
    @classmethod
    def from_str(cls, raw, **kwargs): ...

Generated stub:

class Converter:
    @classmethod
    @overload
    def from_str(cls, raw: str, *, radix: int) -> Converter[int]: ...

    @classmethod
    @overload
    def from_str(cls, raw: str) -> Converter[str]: ...

TypeVar declarations

TypeVar, ParamSpec, TypeVarTuple, and NewType declarations are re-emitted verbatim from the AST pre-pass — the runtime objects are never converted to strings (which would produce ~T on Python 3.12+):

from typing import TypeVar, ParamSpec, NewType

T  = TypeVar("T")
P  = ParamSpec("P")
Nd = TypeVar("Nd", int, float)          # constrained TypeVar
Db = TypeVar("Db", bound="Drawable")    # bound TypeVar

UserId = NewType("UserId", int)

Generated stub:

from typing import NewType, ParamSpec, TypeVar

T  = TypeVar('T')
P  = ParamSpec('P')
Nd = TypeVar('Nd', int, float)
Db = TypeVar('Db', bound='Drawable')

UserId = NewType('UserId', int)

TypeAlias

All TypeAlias forms are detected and preserved:

from typing import TypeAlias

# Explicit PEP 613
Pixels: TypeAlias = int
Color:  TypeAlias = tuple[float, float, float, float]

# Implicit (bare union / subscripted generic)
Length = int | float | str
Matrix = list[list[float]]

# Python 3.12+ PEP 695
# type Vector = list[float]   (emitted as-is when alias_style="pep695")

Generated stub (alias_style="compatible", the default):

from typing import TypeAlias

Pixels: TypeAlias = int
Color:  TypeAlias = tuple[float, float, float, float]
Length: TypeAlias = int | float | str
Matrix: TypeAlias = list[list[float]]