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]"
|
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:
|
def introspect_callable(func: Callable[..., object], name: str) -> FunctionData | None:
|
||||||
"""Introspect a callable (function or builtin) and return its metadata."""
|
"""Introspect a callable (function or builtin) and return its metadata."""
|
||||||
docstring = inspect.getdoc(func) or ""
|
docstring = inspect.getdoc(func) or ""
|
||||||
@ -1032,6 +1052,10 @@ def introspect_callable(func: Callable[..., object], name: str) -> FunctionData
|
|||||||
type_str = doc_type
|
type_str = doc_type
|
||||||
actual_name = doc_name
|
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):
|
if default == "None" and type_str and not re.search(r"\| None\b", type_str):
|
||||||
type_str = type_str + " | None"
|
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)
|
_widen_mathutils_params(params)
|
||||||
return {
|
return {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user