Use @property/@setter for writable mathutils properties

Writable mathutils properties (Vector, Euler, etc.) were typed as plain
attributes with a union type, causing the getter to also return the union.
This made `obj.location.x` fail type checking since Sequence[float] has
no `.x`. Now these properties use @property for the getter (returning the
concrete mathutils type) and @setter accepting the wider union.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-03 15:54:40 +02:00
co-authored by Claude Opus 4.6
parent ace18808ca
commit e4284ce7d9
3 changed files with 79 additions and 22 deletions
+27 -9
View File
@@ -89,6 +89,9 @@ def collect_all_type_strings(module_data: ModuleData) -> list[str]:
all_types.append(base)
for prop in struct["properties"]:
all_types.append(prop["type"])
setter_type = prop.get("setter_type")
if setter_type:
all_types.append(setter_type)
for method in struct["methods"]:
for param in method["params"]:
if param["type"]:
@@ -367,7 +370,9 @@ def generate_property_stub(
property_decorator: str = "@property",
) -> str:
"""Generate a stub for a class property."""
if prop["is_readonly"]:
setter_type = prop.get("setter_type")
if prop["is_readonly"] or setter_type:
result = f"{indent}{property_decorator}\n"
result += f"{indent}def {prop['name']}(self) -> {prop['type']}:\n"
if prop["description"]:
@@ -377,6 +382,11 @@ def generate_property_stub(
result += f'{indent} """{desc}"""\n'
else:
result += f"{indent} ...\n"
if setter_type:
result += f"\n{indent}@{prop['name']}.setter\n"
result += (
f"{indent}def {prop['name']}(self, value: {setter_type}) -> None: ...\n"
)
return result
result = f"{indent}{prop['name']}: {prop['type']}\n"
@@ -413,6 +423,7 @@ def fixup_shadowed_builtins(
fixed: list[PropertyData] = []
for prop in properties:
new_type = prop["type"]
new_setter_type = prop.get("setter_type")
for name in shadowed:
# Replace bare builtin type references with builtins.X
# e.g. "int" -> "builtins.int", "list[int]" -> "list[builtins.int]"
@@ -421,14 +432,21 @@ def fixup_shadowed_builtins(
f"builtins.{name}",
new_type,
)
fixed.append(
{
"name": prop["name"],
"type": new_type,
"is_readonly": prop["is_readonly"],
"description": prop["description"],
}
)
if new_setter_type:
new_setter_type = re.sub(
rf"\b{name}\b",
f"builtins.{name}",
new_setter_type,
)
new_prop: PropertyData = {
"name": prop["name"],
"type": new_type,
"is_readonly": prop["is_readonly"],
"description": prop["description"],
}
if new_setter_type:
new_prop["setter_type"] = new_setter_type
fixed.append(new_prop)
return fixed