Clean up dead code, fix type errors, and add publish workflow
Remove unused _append_ops_call_method, fix _property_data_from_member call signature, replace sys.version_info guard with hasattr check for __buffer__ protocol, fix implicit string concatenations, add msgbus overrides for 4.0-4.4, add conformance tests, and add publish script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+34
-32
@@ -172,6 +172,15 @@ def _requires_builtins_import(module_data: ModuleData) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _has_override_methods(module_data: ModuleData) -> bool:
|
||||
"""Check if any method in the module has is_override set."""
|
||||
for struct in module_data.get("structs", []):
|
||||
for method in struct["methods"]:
|
||||
if method.get("is_override", False):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def collect_imports(module_data: ModuleData) -> set[str]:
|
||||
"""Collect all import statements needed for the stub file."""
|
||||
all_types = collect_all_type_strings(module_data)
|
||||
@@ -179,6 +188,9 @@ def collect_imports(module_data: ModuleData) -> set[str]:
|
||||
imports = _collect_token_imports(joined) | _collect_module_reference_imports(joined)
|
||||
if _requires_builtins_import(module_data):
|
||||
imports.add("import builtins")
|
||||
if _has_override_methods(module_data):
|
||||
# override is in typing since 3.12, typing_extensions for 3.11
|
||||
imports.add("from typing_extensions import override")
|
||||
|
||||
return imports
|
||||
|
||||
@@ -367,28 +379,6 @@ def generate_property_stub(
|
||||
result += f"{indent} ...\n"
|
||||
return result
|
||||
|
||||
# Writable properties with different getter/setter types need @property
|
||||
# (e.g. location: mathutils.Vector | Sequence[float] -> getter returns Vector,
|
||||
# setter accepts both)
|
||||
if " | " in prop["type"]:
|
||||
parts_list = [p.strip() for p in prop["type"].split(" | ")]
|
||||
getter_type = parts_list[0]
|
||||
setter_type = prop["type"]
|
||||
result = f"{indent}{property_decorator}\n"
|
||||
result += f"{indent}def {prop['name']}(self) -> {getter_type}:\n"
|
||||
if prop["description"]:
|
||||
desc = prop["description"].replace("\\", "\\\\").replace('"""', r"\"\"\"")
|
||||
if desc.endswith('"'):
|
||||
desc += " "
|
||||
result += f'{indent} """{desc}"""\n'
|
||||
else:
|
||||
result += f"{indent} ...\n"
|
||||
result += f"{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"
|
||||
if prop["description"]:
|
||||
desc = prop["description"].replace("\\", "\\\\").replace('"""', r"\"\"\"")
|
||||
@@ -478,7 +468,9 @@ def generate_struct_stub(
|
||||
has_body = True
|
||||
|
||||
for method in struct["methods"]:
|
||||
is_override = method["name"] in inherited_methods
|
||||
is_override = method["name"] in inherited_methods or method.get(
|
||||
"is_override", False
|
||||
)
|
||||
parts.append(generate_method_stub(method, is_override=is_override))
|
||||
has_body = True
|
||||
|
||||
@@ -513,10 +505,14 @@ def topological_sort_structs(structs: list[StructData]) -> list[StructData]:
|
||||
class _InheritedInfo:
|
||||
methods: set[str]
|
||||
readonly_props: set[str]
|
||||
all_props: set[str]
|
||||
|
||||
def __init__(self, methods: set[str], readonly_props: set[str]):
|
||||
def __init__(
|
||||
self, methods: set[str], readonly_props: set[str], all_props: set[str]
|
||||
):
|
||||
self.methods = methods
|
||||
self.readonly_props = readonly_props
|
||||
self.all_props = all_props
|
||||
|
||||
|
||||
def collect_inherited_info(
|
||||
@@ -531,7 +527,7 @@ def collect_inherited_info(
|
||||
return cache[name]
|
||||
struct = by_name.get(name)
|
||||
if not struct or not struct["base"]:
|
||||
cache[name] = _InheritedInfo(set(), set())
|
||||
cache[name] = _InheritedInfo(set(), set(), set())
|
||||
return cache[name]
|
||||
base = struct["base"]
|
||||
if base in by_name:
|
||||
@@ -539,13 +535,16 @@ def collect_inherited_info(
|
||||
base_ro_props = {
|
||||
p["name"] for p in by_name[base]["properties"] if p["is_readonly"]
|
||||
}
|
||||
base_all_props = {p["name"] for p in by_name[base]["properties"]}
|
||||
else:
|
||||
base_methods: set[str] = set()
|
||||
base_ro_props: set[str] = set()
|
||||
base_all_props: set[str] = set()
|
||||
parent = get_inherited(base)
|
||||
cache[name] = _InheritedInfo(
|
||||
base_methods | parent.methods,
|
||||
base_ro_props | parent.readonly_props,
|
||||
base_all_props | parent.all_props,
|
||||
)
|
||||
return cache[name]
|
||||
|
||||
@@ -562,7 +561,9 @@ def _generate_context_dict(context_struct: StructData) -> str:
|
||||
can return a precisely typed dict instead of dict[str, object].
|
||||
"""
|
||||
lines: list[str] = ["class ContextDict(TypedDict):"]
|
||||
lines.append(' """Dictionary returned by Context.copy() with all context members."""')
|
||||
lines.append(
|
||||
' """Dictionary returned by Context.copy() with all context members."""'
|
||||
)
|
||||
method_names = {m["name"] for m in context_struct["methods"]}
|
||||
for prop in context_struct["properties"]:
|
||||
if prop["name"] in method_names:
|
||||
@@ -648,12 +649,13 @@ def generate_types_stub(
|
||||
_patch_context_copy_return_type(context_struct)
|
||||
|
||||
for struct in sorted_structs:
|
||||
info = inherited_map.get(struct["name"], _InheritedInfo(set(), set()))
|
||||
# Force writable properties to readonly when they override a parent's
|
||||
# readonly @property (avoids reportIncompatibleMethodOverride)
|
||||
for prop in struct["properties"]:
|
||||
if not prop["is_readonly"] and prop["name"] in info.readonly_props:
|
||||
prop["is_readonly"] = True
|
||||
info = inherited_map.get(struct["name"], _InheritedInfo(set(), set(), set()))
|
||||
# Skip properties already defined on a parent class — re-emitting them
|
||||
# can cause reportIncompatibleVariableOverride or reportImplicitOverride
|
||||
# when RNA subtypes differ (e.g., FunctionNodeInputColor.color vs Node.color)
|
||||
struct["properties"] = [
|
||||
p for p in struct["properties"] if p["name"] not in info.all_props
|
||||
]
|
||||
# Emit ContextDict TypedDict right before the Context class
|
||||
if struct["name"] == "Context":
|
||||
parts.append("")
|
||||
|
||||
Reference in New Issue
Block a user