Special class forms¶
stubpy generates clean, correct stubs for every major Python class pattern. This page shows what each form produces.
NamedTuple¶
Fields are emitted in declaration order with type annotations. Any extra
methods (@property, custom helpers) are preserved; auto-generated
internals (_make, _asdict, _replace) are suppressed:
from typing import NamedTuple
class BoundingBox(NamedTuple):
x: float
y: float
width: float
height: float
@property
def right(self) -> float:
return self.x + self.width
def area(self) -> float:
return self.width * self.height
Generated stub:
class BoundingBox(NamedTuple):
x: float
y: float
width: float
height: float
@property
def right(self) -> float: ...
def area(self) -> float: ...
dataclass¶
A synthesised __init__ is built from __dataclass_fields__.
ClassVar fields are emitted as class annotations, not init parameters.
default_factory fields show as field: Type = ...:
from dataclasses import dataclass, field
from typing import ClassVar
@dataclass
class StrokeStyle:
color: tuple = (0.0, 0.0, 0.0, 1.0)
width: float = 1.0
dash_pattern: list[float] = field(default_factory=list)
_cache: ClassVar[dict]
Generated stub:
@dataclass
class StrokeStyle:
color: tuple
width: float
dash_pattern: list[float]
_cache: ClassVar[dict]
def __init__(
self,
color: tuple = (0.0, 0.0, 0.0, 1.0),
width: float = 1.0,
dash_pattern: list[float] = ...,
) -> None: ...
TypedDict¶
Emitted as class Name(TypedDict): or class Name(TypedDict, total=False):.
Field annotations are pulled from __annotations__:
from typing import TypedDict
class RenderOptions(TypedDict, total=False):
compact: bool
indent: str
dpi: float
Generated stub:
class RenderOptions(TypedDict, total=False):
compact: bool
indent: str
dpi: float
Enum / IntEnum¶
The correct base class is detected (Enum, IntEnum, StrEnum, etc.)
and a from enum import … import is injected automatically. Internal
implementation methods (_generate_next_value_, _missing_) are
suppressed. Enum member defaults in other classes are rendered as
ClassName.MEMBER, not the unreadable repr():
import enum
class BlendMode(enum.Enum):
NORMAL = "normal"
MULTIPLY = "multiply"
SCREEN = "screen"
class Shape:
def __init__(self, blend_mode: BlendMode = BlendMode.NORMAL): ...
Generated stubs:
from enum import Enum
class BlendMode(Enum):
def __new__(self, value) -> None: ...
class Shape:
# Note: BlendMode.NORMAL — not <BlendMode.NORMAL: 'normal'>
def __init__(self, blend_mode: BlendMode = BlendMode.NORMAL): ...
Abstract base class¶
@abstractmethod and the ABC base class are handled:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def render(self, *, compact: bool = False) -> str: ...
def describe(self) -> str: ... # concrete
Generated stub:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def render(self, *, compact: bool = False) -> str: ...
def describe(self) -> str: ...
Generic classes¶
Generic[T] base classes are preserved via __orig_bases__ (PEP 560):
from typing import Generic, TypeVar, Iterator
T = TypeVar("T")
class Stack(Generic[T]):
def push(self, item: T) -> None: ...
def pop(self) -> T: ...
def __iter__(self) -> Iterator[T]: ...
Generated stub:
from typing import Generic, Iterator, TypeVar
T = TypeVar('T')
class Stack(Generic[T]):
def push(self, item: T) -> None: ...
def pop(self) -> T: ...
def __iter__(self) -> Iterator[T]: ...
Protocol¶
@runtime_checkable Protocol classes are emitted correctly:
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def render(self, *, compact: bool = False) -> str: ...
Generated stub:
from typing import Protocol
class Drawable(Protocol):
def render(self, *, compact: bool = False) -> str: ...