stubpy.annotations¶
stubpy.annotations¶
Annotation-to-string conversion using a registered dispatch table.
The central function annotation_to_str() converts any live Python
annotation object to a stub-safe string. Each annotation kind is handled
by a small private function registered via @_register(predicate). Adding
support for a new annotation type is a single decorated function — no
editing of an if/elif chain.
Resolution order inside annotation_to_str():
inspect.Parameter.empty→""Alias-registry lookup → e.g.
"types.Length"Registered dispatch handlers, in registration order
Fallback:
str(annotation).replace("typing.", "")
Core functions
- annotation_to_str(annotation: Any, ctx: StubContext) str[source]¶
Convert any annotation object to a valid
.pyistring.Resolution order:
inspect.Parameter.emptyorinspect.Signature.empty→""Alias-registry lookup via
lookup_alias()— if the annotation matches a registered alias it is returned as-is (e.g."types.Length") and the alias module is marked as used.Registered dispatch handlers, tried in order.
Fallback:
str(annotation).replace("typing.", "").
This function is recursive — generic argument lists are processed by calling it on each
__args__element.- Parameters:
annotation (Any) – Any live Python annotation object. Accepted values include plain types (
int,str), PEP 604 unions (str | None), subscripted typing generics (Optional[int]), string forward references ("Element"),typing.ForwardRefobjects,NoneType, andinspect.Parameter.empty.ctx (StubContext) – The current
StubContext. Used for alias lookup and to track which type-module imports are needed.
- Returns:
str – A stub-safe string representation, or
""for empty sentinels.
See also
format_paramFormats a full parameter including name and default.
stubpy.context.StubContext.lookup_aliasAlias resolution logic.
Examples
>>> from stubpy.context import StubContext >>> from stubpy.annotations import annotation_to_str >>> from typing import Optional, List >>> ctx = StubContext() >>> annotation_to_str(int, ctx) 'int' >>> annotation_to_str(str | None, ctx) 'Optional[str]' >>> annotation_to_str(List[int], ctx) 'List[int]' >>> annotation_to_str("Element", ctx) 'Element' >>> annotation_to_str(type(None), ctx) 'None'
- format_param(param: Parameter, hints: dict[str, Any], ctx: StubContext) str[source]¶
Format a single
inspect.Parameteras a stub-ready string.The hints dict (from
get_hints_for_method()) takes priority overparam.annotationbecause it contains fully resolved annotations — forward references evaluated,from __future__ import annotationsstrings expanded.- Parameters:
param (inspect.Parameter) – The parameter to format.
hints (dict) – Resolved type hints for the owning function, keyed by parameter name. Falls back to
param.annotationwhen the name is absent.ctx (StubContext) – The current
StubContext, passed through toannotation_to_str().
- Returns:
str – A formatted string such as
"x: int","size: float = 1.0","*args: str", or"**kwargs".
Examples
>>> import inspect >>> from stubpy.context import StubContext >>> from stubpy.annotations import format_param >>> ctx = StubContext() >>> p = inspect.Parameter("x", inspect.Parameter.POSITIONAL_OR_KEYWORD, ... annotation=int, default=0) >>> format_param(p, {}, ctx) 'x: int = 0' >>> p_star = inspect.Parameter("items", inspect.Parameter.VAR_POSITIONAL, ... annotation=str) >>> format_param(p_star, {"items": str}, ctx) '*items: str'
- get_hints_for_method(fn: Any) dict[str, Any][source]¶
Safely resolve type hints for fn, unwrapping descriptors first.
- Parameters:
fn (Any) – A callable,
classmethod,staticmethod, orproperty.Nonereturns an empty dict.- Returns:
dict –
{param_name: annotation}with forward references resolved, or an empty dict if resolution fails or fn isNone.
Examples
>>> class A: ... def foo(self, x: int) -> str: ... >>> get_hints_for_method(A.foo) {'x': <class 'int'>, 'return': <class 'str'>}
- default_to_str(default: Any) str[source]¶
Render a parameter default value as a stub-safe string.
- Parameters:
default (Any) – The default value, or
inspect.Parameter.emptywhen the parameter has no default.- Returns:
str –
repr(default)for real defaults, or""for the empty sentinel.
Examples
>>> import inspect >>> default_to_str(inspect.Parameter.empty) '' >>> default_to_str("black") "'black'" >>> default_to_str(1.0) '1.0' >>> default_to_str(None) 'None'
Extending the dispatch table
New annotation kinds can be supported by registering a handler with the
internal _register decorator:
from stubpy.annotations import _register
from stubpy.context import StubContext
@_register(lambda a: isinstance(a, MyAnnotationType))
def _handle_my_annotation(annotation, ctx: StubContext) -> str:
return f"MyAlias[{annotation.inner}]"
Built-in handlers (in dispatch order):
Predicate |
Handles |
|---|---|
|
String forward references, e.g. |
|
|
|
|
|
PEP 604 |
|
Plain classes — uses |
|
All subscripted typing generics (Union, Optional, Callable, Literal, …) |
|
Bare unsubscripted aliases ( |