stubpy.resolver

stubpy.resolver

Parameter resolution — the core **kwargs / *args backtracing logic.

resolve_params() returns the fully-merged parameter list for any method, expanding variadic arguments into the concrete named parameters they absorb by walking the class MRO or detecting cls(**kwargs) patterns via AST analysis.

resolve_params(cls: type, method_name: str) list[tuple[Parameter, dict[str, Any]]][source]

Return the fully-merged parameter list for method_name on cls.

Expands **kwargs and *args into the concrete parameters they absorb using one of three strategies applied in order:

  1. No variadics — if the method has neither *args nor **kwargs, return its own parameters unchanged.

  2. cls()-call detection — if the method is a @classmethod whose body contains cls(..., **kwargs), resolve against cls.__init__. Parameters hardcoded in the call are excluded.

  3. MRO walk — iterate ancestors that define the same method, collecting concrete parameters until all variadics are resolved.

self and cls are always excluded from the result.

Parameters:
  • cls (type) – The class owning (or inheriting) the method.

  • method_name (str) – Name of the method to resolve.

Returns:

list of ParamWithHints – Ordered (Parameter, hints_dict) tuples. Own parameters come first, then ancestor parameters in MRO order. Unresolvable **kwargs and explicitly-typed *args are appended last.

See also

stubpy.emitter.generate_method_stub

Consumes the output of this function.

Examples

>>> class Base:
...     def __init__(self, color: str, opacity: float = 1.0) -> None: ...
>>> class Child(Base):
...     def __init__(self, label: str, **kwargs) -> None: ...
>>> params = resolve_params(Child, "__init__")
>>> [p.name for p, _ in params]
['label', 'color', 'opacity']

Resolution strategies

resolve_params() applies three strategies in order:

  1. No variadics — return own parameters unchanged.

  2. @classmethod cls() detection — AST analysis; resolves **kwargs against cls.__init__. Hardcoded arguments are excluded.

  3. MRO walk — collect concrete params from each ancestor until all variadics are resolved or the MRO is exhausted.

Parameter ordering

  1. The method’s own concrete parameters (original order)

  2. Parameters from the first MRO ancestor that defines the method

  3. Parameters from further ancestors, in MRO order

  4. Preserved *args (if explicitly typed or unresolvable) — always placed before any keyword-only params and before **kwargs

  5. Residual **kwargs (if the chain was never fully resolved)

*args preservation

A *args parameter is kept when either:

  • The MRO walk could not resolve it (still_var_pos remains True).

  • The *args carries an explicit annotation (e.g. *elements: Element), indicating a typed variadic.

In both cases *args is inserted before the first keyword-only parameter and before any trailing **kwargs, so the emitted signature is always syntactically valid Python.