Fix typecheck errors across all Blender versions

- Strip single backtick RST markup from type annotations (` int ` -> int)
- Convert "string in ['X', 'Y']" docstring patterns to Literal types
- Map undefined ContextTempOverride type to object
- Add Callable import to bpy.types stub generator
- Fix Callable[[object, ...], X] -> Callable[..., X] for varargs
- Fix Literal[...] = False incompatible defaults to use ...
- Include classmethod-wrapped C builtins in RNA type C-method scan

Remaining pre-existing errors:
- 4.0-4.3: Sequence name clash with bpy.types.Sequence
- 4.0: Node.type structural RNA conflict
- 5.1: BMElemSeq/BMLayerCollection not declared as generic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph HENRY 2026-03-27 11:33:22 +01:00
parent b3b282d8b0
commit 6ecd996f35
2 changed files with 31 additions and 2 deletions

View File

@ -176,10 +176,14 @@ def format_param(param: ParamData, force_type: bool = False) -> str:
parts.append(f": {type_str}")
if param["default"] is not None:
default = param["default"]
# Fix incompatible defaults: Literal types can't have bool defaults
if type_str and "Literal[" in type_str and default in ("False", "True"):
default = "..."
if type_str:
parts.append(f" = {param['default']}")
parts.append(f" = {default}")
else:
parts.append(f"={param['default']}")
parts.append(f"={default}")
return "".join(parts)
@ -552,6 +556,8 @@ def generate_types_stub(
typing_imports.append("Literal")
abc_imports = ["Iterator"]
if "Callable" in all_type_strs:
abc_imports.append("Callable")
if "MutableSequence[" in all_type_strs:
abc_imports.append("MutableSequence")
# Only import bare Sequence if used without collections.abc. prefix

View File

@ -322,12 +322,24 @@ def clean_type_str(type_str: str) -> str:
type_str = re.sub(r":class:`([^`]+)`", r"\1", type_str)
# Remove double backtick RST markup
type_str = re.sub(r"``([^`]+)``", r"\1", type_str)
# Remove single backtick markup (` int ` → int)
type_str = re.sub(r"`\s*([^`]+?)\s*`", r"\1", type_str)
# Strip leaked RST directives from type strings
type_str = re.sub(r"\.?\s*(?:r?type|returns?):.*", "", type_str)
# Strip stray RST role colons but not :param, :arg, :type directives
type_str = re.sub(r":(?!param|arg|type|return)(\w)", r"\1", type_str)
type_str = type_str.rstrip(":.,")
# Convert "string in ['X', 'Y', ...]" to Literal["X", "Y", ...]
str_in_match = re.match(
r"str(?:ing)?\s+in\s+\[([^\]]+)\]", type_str, re.IGNORECASE
)
if str_in_match:
values = re.findall(r"'([^']+)'", str_in_match.group(1))
if values:
quoted = ", ".join(f'"{v}"' for v in values)
return f"Literal[{quoted}]"
# Convert tuple(X, Y) to tuple[X, Y] (docstrings sometimes use parens)
type_str = re.sub(r"\btuple\(([^)]+)\)", r"tuple[\1]", type_str)
@ -480,6 +492,10 @@ def clean_type_str(type_str: str) -> str:
# Bare generics without params -> add default params.
# Use \b on both sides to avoid matching inside longer names (e.g. SequenceEntry).
type_str = re.sub(r"\bCallable\b(?!\[)", "Callable[..., object]", type_str)
# Fix Callable[[..., ...], X] or Callable[[object, ...], X] -> Callable[..., X]
type_str = re.sub(
r"Callable\[\[[^\]]*\.\.\.[^\]]*\]", "Callable[...", type_str
)
type_str = re.sub(r"\bdict\b(?!\[)", "dict[str, object]", type_str)
type_str = re.sub(r"\blist\b(?!\[)", "list[object]", type_str)
type_str = re.sub(r"\btuple\b(?!\[)", "tuple[object, ...]", type_str)
@ -682,6 +698,13 @@ def clean_type_str(type_str: str) -> str:
):
type_str = "object"
# Map types that exist in docstrings but not in the Blender Python API
_UNDEFINED_TYPE_MAP = {
"ContextTempOverride": "object",
}
if type_str in _UNDEFINED_TYPE_MAP:
return _UNDEFINED_TYPE_MAP[type_str]
# Final balance check — catch any remaining malformed types
if type_str.count("[") != type_str.count("]") or type_str.count(
"("