Add ContextTempOverride as context manager, support __enter__/__exit__ dunders
- Discover ContextTempOverride by probing Context.temp_override() return value - Add __enter__ and __exit__ to _USEFUL_DUNDERS set - Fix __enter__ return type to Self, __exit__ params to standard CM signature - Add Self import to bpy.types generator when used in type annotations - Remove ContextTempOverride from undefined type map (now a real class) Remaining conformance issue: context.copy() returns dict[str, object] which loses specific types when unpacked with **kwargs into temp_override params. This is an inherent limitation of the copy() -> dict pattern. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a30e772cf8
commit
80d5311e33
@ -553,6 +553,8 @@ def generate_types_stub(
|
||||
typing_imports = ["Generic", "TypeVar"]
|
||||
if "Literal[" in all_type_strs:
|
||||
typing_imports.append("Literal")
|
||||
if re.search(r"\bSelf\b", all_type_strs):
|
||||
typing_imports.append("Self")
|
||||
|
||||
abc_imports = ["Iterator"]
|
||||
if "Callable" in all_type_strs:
|
||||
|
||||
@ -542,9 +542,7 @@ _UNDEFINED_TYPE_NAMES = {
|
||||
"_PropertyDeferred",
|
||||
}
|
||||
|
||||
_UNDEFINED_TYPE_MAP = {
|
||||
"ContextTempOverride": "object",
|
||||
}
|
||||
_UNDEFINED_TYPE_MAP: dict[str, str] = {}
|
||||
|
||||
_UNDEFINED_GENERIC_TYPES = {"BMVertSkin"}
|
||||
|
||||
@ -1226,6 +1224,8 @@ _USEFUL_DUNDERS = {
|
||||
"__le__",
|
||||
"__gt__",
|
||||
"__ge__",
|
||||
"__enter__",
|
||||
"__exit__",
|
||||
}
|
||||
|
||||
|
||||
@ -1293,6 +1293,7 @@ def _fix_dunder_signatures(
|
||||
"__ge__": "bool",
|
||||
"__delitem__": "None",
|
||||
"__setitem__": "None",
|
||||
"__exit__": "None",
|
||||
}
|
||||
for method in methods:
|
||||
fixed = _FIXED_RETURNS.get(method["name"])
|
||||
@ -1300,6 +1301,15 @@ def _fix_dunder_signatures(
|
||||
method["return_type"] = fixed
|
||||
if method["name"] == "__len__":
|
||||
method["params"] = []
|
||||
if method["name"] == "__enter__":
|
||||
method["return_type"] = "Self"
|
||||
method["params"] = []
|
||||
if method["name"] == "__exit__":
|
||||
method["params"] = [
|
||||
{"name": "exc_type", "type": "type[BaseException] | None", "default": None, "kind": "POSITIONAL_OR_KEYWORD"},
|
||||
{"name": "exc_val", "type": "BaseException | None", "default": None, "kind": "POSITIONAL_OR_KEYWORD"},
|
||||
{"name": "exc_tb", "type": "object", "default": None, "kind": "POSITIONAL_OR_KEYWORD"},
|
||||
]
|
||||
if method["name"] == "__delitem__":
|
||||
method["params"] = [
|
||||
{
|
||||
@ -2680,6 +2690,31 @@ def introspect_rna_types() -> ModuleData:
|
||||
_merge_non_rna_bpy_types(structs, _bpy_types)
|
||||
_merge_missing_c_methods(structs, _bpy_types)
|
||||
|
||||
# Discover hidden C types reachable only via method return values
|
||||
# (e.g. ContextTempOverride from Context.temp_override()).
|
||||
known = {s["name"] for s in structs}
|
||||
bpy = importlib.import_module("bpy")
|
||||
ctx = getattr(bpy, "context")
|
||||
_HIDDEN_TYPE_PROBES: list[tuple[object, str]] = [
|
||||
(ctx, "temp_override"),
|
||||
]
|
||||
for obj, method_name in _HIDDEN_TYPE_PROBES:
|
||||
func = getattr(obj, method_name, None)
|
||||
if func is None or not callable(func):
|
||||
continue
|
||||
try:
|
||||
result = func()
|
||||
result_cls = result.__class__
|
||||
if result_cls.__name__ not in known:
|
||||
structs.append(introspect_class(result_cls, "bpy.types"))
|
||||
known.add(result_cls.__name__)
|
||||
# Clean up context manager if applicable
|
||||
exit_fn = getattr(result, "__exit__", None)
|
||||
if exit_fn is not None:
|
||||
exit_fn(None, None, None)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {
|
||||
"module": "bpy.types",
|
||||
"doc": "Blender RNA type definitions.",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user