Read Python type annotations from function signatures
Functions with type hints (e.g. bpy_extras.anim_utils) now have their parameter and return types picked up from inspect.signature annotations, falling back from docstring :type:/:rtype: directives. - Add _annotation_to_type_str to clean annotation strings - Replace _bpy_types.X with bpy.types.X, Union[X, Y] with X | Y - Qualify bare mathutils types (Vector, Matrix, etc.) - Normalize NoneType to None Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f0affebaa3
commit
b4158d8ca2
@ -944,6 +944,26 @@ def _widen_mathutils_params(params: list[ParamData]) -> None:
|
||||
param["type"] = f"{ptype} | Sequence[float]"
|
||||
|
||||
|
||||
def _annotation_to_type_str(ann: object) -> str:
|
||||
"""Convert a Python annotation object to a clean type string for stubs."""
|
||||
s = ann if isinstance(ann, str) else str(ann)
|
||||
# Clean up internal module references
|
||||
s = s.replace("_bpy_types.", "bpy.types.")
|
||||
# typing.Union[X, Y] -> X | Y
|
||||
s = re.sub(r"\bUnion\[([^\]]+)\]", lambda m: " | ".join(m.group(1).split(", ")), s)
|
||||
# typing.Optional[X] -> X | None
|
||||
s = re.sub(r"\bOptional\[([^\]]+)\]", r"\1 | None", s)
|
||||
# <class 'int'> -> int
|
||||
s = re.sub(r"<class '([^']+)'>", r"\1", s)
|
||||
s = s.replace("typing.", "")
|
||||
# NoneType -> None
|
||||
s = re.sub(r"\bNoneType\b", "None", s)
|
||||
# Qualify bare mathutils types (avoid double-qualifying already-qualified ones)
|
||||
for mt in ("Vector", "Matrix", "Euler", "Quaternion", "Color"):
|
||||
s = re.sub(rf"(?<!\.)(?<!\w)\b{mt}\b", f"mathutils.{mt}", s)
|
||||
return s
|
||||
|
||||
|
||||
def introspect_callable(func: Callable[..., object], name: str) -> FunctionData | None:
|
||||
"""Introspect a callable (function or builtin) and return its metadata."""
|
||||
docstring = inspect.getdoc(func) or ""
|
||||
@ -1032,6 +1052,10 @@ def introspect_callable(func: Callable[..., object], name: str) -> FunctionData
|
||||
type_str = doc_type
|
||||
actual_name = doc_name
|
||||
|
||||
# Fall back to signature annotations (Python functions with type hints)
|
||||
if type_str is None and param.annotation is not inspect.Parameter.empty:
|
||||
type_str = _annotation_to_type_str(param.annotation)
|
||||
|
||||
if default == "None" and type_str and not re.search(r"\| None\b", type_str):
|
||||
type_str = type_str + " | None"
|
||||
|
||||
@ -1044,6 +1068,10 @@ def introspect_callable(func: Callable[..., object], name: str) -> FunctionData
|
||||
}
|
||||
)
|
||||
|
||||
# Fall back to signature return annotation
|
||||
if return_type is None and sig.return_annotation is not inspect.Signature.empty:
|
||||
return_type = _annotation_to_type_str(sig.return_annotation)
|
||||
|
||||
_widen_mathutils_params(params)
|
||||
return {
|
||||
"name": name,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user