stubpy.emitter¶
stubpy.emitter¶
Stub text generation — converts live class objects into .pyi source.
Two formatting modes are chosen automatically:
Inline for methods with ≤ 2 non-self/cls parameters.
Multi-line for methods with > 2 parameters, each on its own indented line with a trailing comma for clean diffs.
- generate_class_stub(cls: type, ctx: StubContext) str[source]¶
Generate the full
.pyiblock for cls.Emits in order:
class Name(Base, ...):line.Class-level annotations from
cls.__dict__["__annotations__"].A blank line after annotations when present.
One stub per public method defined directly on cls.
...when the class has neither annotations nor methods.
- Parameters:
cls (type) – The class to stub.
ctx (StubContext) – The current
StubContext.
- Returns:
str – Complete class stub as a multi-line string without a trailing newline.
Examples
>>> from stubpy.context import StubContext >>> class Point: ... x: float ... y: float ... def __init__(self, x: float, y: float) -> None: ... >>> stub = generate_class_stub(Point, StubContext()) >>> "class Point:" in stub True >>> "x: float" in stub True
- generate_method_stub(cls: type, method_name: str, ctx: StubContext, indent: str = ' ') str[source]¶
Generate the
.pyistub line(s) for a single method on cls.Dispatches on the descriptor type in
cls.__dict__:property—@propertywith optional@name.setter.classmethod—@classmethodwithclsfirst.staticmethod—@staticmethodwith no implicit first parameter.Regular method —
selfas first parameter.
Methods with ≤ 2 non-self params are formatted inline; larger signatures are split across lines with a trailing comma on each parameter.
- Parameters:
cls (type) – The class that owns the method.
method_name (str) – Name of the method as it appears in
cls.__dict__.ctx (StubContext) – The current
StubContext.indent (str, optional) – Indentation string prepended to each line. Default is four spaces.
- Returns:
str – One or more stub lines, or
""if method_name is not incls.__dict__.
Examples
>>> from stubpy.context import StubContext >>> class A: ... def move(self, x: float, y: float) -> None: ... >>> stub = generate_method_stub(A, "move", StubContext()) >>> stub ' def move(self, x: float, y: float) -> None: ...'
- methods_defined_on(cls: type) list[str][source]¶
Return names of callable members defined directly on cls.
Only inspects
cls.__dict__— inherited members are excluded. Dunder names not in_PUBLIC_DUNDERSare silently skipped. Insertion order is preserved.- Parameters:
cls (type) – The class to inspect.
- Returns:
list of str – Method names (including classmethods, staticmethods, properties) defined on cls that should appear in a stub.
Examples
>>> class Parent: ... def parent_method(self) -> None: ... >>> class Child(Parent): ... def child_method(self) -> None: ... >>> methods_defined_on(Child) ['child_method']
- insert_kw_separator(params_with_hints: list[tuple[Parameter, dict[str, Any]]]) list[tuple[Parameter, dict[str, Any]]][source]¶
Insert a bare
*sentinel before the first keyword-only parameter.Python requires a bare
*(or a*args) before any keyword-only parameters in a function signature. When no*argsis present but keyword-only parameters exist, this function inserts a sentinelinspect.Parameternamed_KW_SEP_NAMEthatgenerate_method_stub()emits as a literal*.If a
VAR_POSITIONAL(*args) parameter is already present no sentinel is needed and the list is returned unchanged.- Parameters:
params_with_hints (list of ParamWithHints) – The parameter list from
resolve_params().- Returns:
list of ParamWithHints – The same list with the sentinel inserted at the correct position, or the original list unchanged if no insertion is needed.
Examples
>>> import inspect >>> kw = inspect.Parameter("b", inspect.Parameter.KEYWORD_ONLY) >>> pos = inspect.Parameter("a", inspect.Parameter.POSITIONAL_OR_KEYWORD) >>> result = insert_kw_separator([(pos, {}), (kw, {})]) >>> result[1][0].name # sentinel is between a and b '__kw_sep__'
Formatting rules
Inline (≤ 2 non-self/cls parameters):
def area(self) -> float: ...
def scale(self, sx: float, sy: Optional[float] = None) -> Element: ...
Multi-line (> 2 non-self/cls parameters), each param on its own line with a trailing comma:
def __init__(
self,
width: float,
height: float,
depth: float = 1.0,
) -> None: ...
Trailing commas make diffs cleaner — adding or removing a parameter changes exactly one line.
Public dunders
Only the methods listed in the internal _PUBLIC_DUNDERS set are
included in stubs. Internal Python machinery names (__dict__,
__weakref__, __class__, etc.) are omitted.