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:
+353
-83
@@ -176,7 +176,11 @@ class ParamData(TypedDict):
|
||||
kind: str
|
||||
|
||||
|
||||
class FunctionData(TypedDict):
|
||||
class _FunctionDataOptional(TypedDict, total=False):
|
||||
is_override: bool
|
||||
|
||||
|
||||
class FunctionData(_FunctionDataOptional):
|
||||
name: str
|
||||
doc: str
|
||||
params: list[ParamData]
|
||||
@@ -494,6 +498,12 @@ _CLEAN_TYPE_ALIAS_RULES: tuple[RegexRule, ...] = (
|
||||
(re.compile(r"\bfunction\b"), "Callable[..., object]"),
|
||||
(re.compile(r"\bgenerator\b"), "Generator"),
|
||||
(re.compile(r"\bsequence\b"), "Sequence"),
|
||||
# Old typing module names -> modern builtins
|
||||
(re.compile(r"\bDict\b"), "dict"),
|
||||
(re.compile(r"\bList\b"), "list"),
|
||||
(re.compile(r"\bTuple\b"), "tuple"),
|
||||
(re.compile(r"\bSet\b(?!tings)"), "set"),
|
||||
(re.compile(r"\bFrozenSet\b"), "frozenset"),
|
||||
)
|
||||
|
||||
_CLEAN_TYPE_GENERIC_RULES: tuple[RegexRule, ...] = (
|
||||
@@ -501,7 +511,8 @@ _CLEAN_TYPE_GENERIC_RULES: tuple[RegexRule, ...] = (
|
||||
(re.compile(r"\s*\|\s*\d+\b"), ""),
|
||||
(re.compile(r"(\w)\[\]"), r"\1"),
|
||||
(re.compile(r"\bCallable\b(?!\[)"), "Callable[..., object]"),
|
||||
(re.compile(r"Callable\[\[[^\]]*\.\.\.[^\]]*\]"), "Callable[...,"),
|
||||
# Callable[[...], X] -> Callable[..., X] (consume trailing comma)
|
||||
(re.compile(r"Callable\[\[[^\]]*\.\.\.[^\]]*\],?\s*"), "Callable[..., "),
|
||||
(re.compile(r"\bdict\b(?!\[)"), "dict[str, object]"),
|
||||
(re.compile(r"\blist\b(?!\[)"), "list[object]"),
|
||||
(re.compile(r"\btuple\b(?!\[)"), "tuple[object, ...]"),
|
||||
@@ -662,7 +673,7 @@ def clean_type_str(type_str: str) -> str:
|
||||
type_str = re.sub(rf"\b{re.escape(undef)}\b(\.\w+)*", "object", type_str)
|
||||
|
||||
# Map known unqualified Python stdlib types
|
||||
type_str = re.sub(r"\bModule\b", "types.ModuleType", type_str)
|
||||
type_str = re.sub(r"\b[Mm]odule\b", "types.ModuleType", type_str)
|
||||
|
||||
# Fix GPU types wrongly referenced as bpy.types.GPU* (Blender docstring bug in 4.x)
|
||||
type_str = re.sub(r"\bbpy\.types\.(GPU\w+)\b", r"gpu.types.\1", type_str)
|
||||
@@ -959,6 +970,20 @@ def _annotation_to_type_str(ann: object) -> str:
|
||||
s = s.replace("typing.", "")
|
||||
# NoneType -> None
|
||||
s = re.sub(r"\bNoneType\b", "None", s)
|
||||
# Old typing aliases -> modern builtins
|
||||
s = re.sub(r"\bDict\b", "dict", s)
|
||||
s = re.sub(r"\bList\b", "list", s)
|
||||
s = re.sub(r"\bTuple\b", "tuple", s)
|
||||
s = re.sub(r"\bSet\b(?!tings)", "set", s)
|
||||
s = re.sub(r"\bFrozenSet\b", "frozenset", s)
|
||||
# Bare module type -> types.ModuleType
|
||||
s = re.sub(r"\bmodule\b", "types.ModuleType", s)
|
||||
# Parameterize bare generics (e.g., bare set -> set[object])
|
||||
s = re.sub(r"\bdict\b(?!\[)", "dict[str, object]", s)
|
||||
s = re.sub(r"\blist\b(?!\[)", "list[object]", s)
|
||||
s = re.sub(r"\bset\b(?!\[)", "set[object]", s)
|
||||
s = re.sub(r"\bfrozenset\b(?!\[)", "frozenset[object]", s)
|
||||
s = re.sub(r"\btuple\b(?!\[)", "tuple[object, ...]", 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)
|
||||
@@ -1517,7 +1542,6 @@ def _append_callable_method(
|
||||
def _property_data_from_member(
|
||||
cls: type[object],
|
||||
name: str,
|
||||
obj: object,
|
||||
raw: object,
|
||||
) -> PropertyData:
|
||||
"""Build PropertyData from a property/getset descriptor class member."""
|
||||
@@ -1559,7 +1583,7 @@ def _introspect_declared_class_members(
|
||||
_append_callable_method(methods, obj, name)
|
||||
continue
|
||||
if isinstance(raw, property) or type(raw).__name__ == "getset_descriptor":
|
||||
properties.append(_property_data_from_member(cls, name, obj, raw))
|
||||
properties.append(_property_data_from_member(cls, name, raw))
|
||||
continue
|
||||
properties.append(
|
||||
{
|
||||
@@ -1606,28 +1630,23 @@ def _refine_and_synthesize_dunders(
|
||||
}
|
||||
)
|
||||
|
||||
if sys.version_info >= (3, 12) and "__buffer__" not in method_names:
|
||||
try:
|
||||
instance = cls()
|
||||
memoryview(instance)
|
||||
methods.append(
|
||||
{
|
||||
"name": "__buffer__",
|
||||
"doc": "",
|
||||
"params": [
|
||||
{
|
||||
"name": "flags",
|
||||
"type": "int",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_ONLY",
|
||||
}
|
||||
],
|
||||
"return_type": "memoryview",
|
||||
"is_classmethod": False,
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
if "__buffer__" not in method_names and hasattr(cls, "__buffer__"):
|
||||
methods.append(
|
||||
{
|
||||
"name": "__buffer__",
|
||||
"doc": "",
|
||||
"params": [
|
||||
{
|
||||
"name": "flags",
|
||||
"type": "int",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_ONLY",
|
||||
}
|
||||
],
|
||||
"return_type": "memoryview",
|
||||
"is_classmethod": False,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _collect_public_module_names(module: ModuleType, module_name: str) -> list[str]:
|
||||
@@ -1757,6 +1776,12 @@ def introspect_class(cls: type[object], module_name: str) -> StructData:
|
||||
_insert_constructor_from_doc(cls, class_doc, methods)
|
||||
_refine_and_synthesize_dunders(cls, methods)
|
||||
|
||||
# Mark __eq__/__ne__ as overrides (they override object.__eq__/__ne__)
|
||||
_OBJECT_OVERRIDES = {"__eq__", "__ne__"}
|
||||
for method in methods:
|
||||
if method["name"] in _OBJECT_OVERRIDES:
|
||||
method["is_override"] = True
|
||||
|
||||
return {
|
||||
"name": cls.__name__,
|
||||
"doc": class_doc,
|
||||
@@ -1859,64 +1884,219 @@ def _apply_ops_property_and_method_fixups(op_struct: StructData) -> None:
|
||||
method["return_type"] = "bpy.types.Struct"
|
||||
|
||||
|
||||
def _append_ops_call_method(op_struct: StructData) -> None:
|
||||
"""Append the callable operator wrapper method definition."""
|
||||
op_struct["methods"].append(
|
||||
{
|
||||
"name": "__call__",
|
||||
"doc": "Execute the operator.",
|
||||
"params": [
|
||||
{
|
||||
"name": "args",
|
||||
"type": "object",
|
||||
"default": None,
|
||||
"kind": "VAR_POSITIONAL",
|
||||
},
|
||||
{
|
||||
"name": "kwargs",
|
||||
"type": "object",
|
||||
"default": None,
|
||||
"kind": "VAR_KEYWORD",
|
||||
},
|
||||
],
|
||||
"return_type": "set[str]",
|
||||
"is_classmethod": False,
|
||||
}
|
||||
)
|
||||
_RAW_RNA_TYPE_MAP: dict[str, str] = {
|
||||
"BOOLEAN": "bool",
|
||||
"INT": "int",
|
||||
"FLOAT": "float",
|
||||
"STRING": "str",
|
||||
"ENUM": "str",
|
||||
}
|
||||
|
||||
_VECTOR_SUBTYPES = {
|
||||
"TRANSLATION",
|
||||
"DIRECTION",
|
||||
"VELOCITY",
|
||||
"ACCELERATION",
|
||||
"XYZ",
|
||||
"XYZ_LENGTH",
|
||||
}
|
||||
|
||||
|
||||
def _build_ops_submodule_struct(operator_type_name: str) -> StructData:
|
||||
"""Build synthetic bpy.ops submodule structure for attribute access."""
|
||||
return {
|
||||
"name": "_OpsSubModule",
|
||||
"doc": "Operator submodule (e.g. bpy.ops.mesh).",
|
||||
"base": None,
|
||||
"properties": [],
|
||||
"methods": [
|
||||
{
|
||||
"name": "__getattr__",
|
||||
"doc": "",
|
||||
"params": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "str",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_OR_KEYWORD",
|
||||
},
|
||||
],
|
||||
"return_type": operator_type_name,
|
||||
"is_classmethod": False,
|
||||
def _raw_rna_prop_to_type(prop: object) -> str:
|
||||
"""Convert a raw RNA Property to a type string (for operator params)."""
|
||||
ptype: str = getattr(prop, "type", "")
|
||||
is_array: bool = getattr(prop, "is_array", False)
|
||||
array_length: int = getattr(prop, "array_length", 0)
|
||||
subtype: str = getattr(prop, "subtype", "NONE")
|
||||
|
||||
if ptype == "ENUM":
|
||||
items = list(getattr(prop, "enum_items", []))
|
||||
if items:
|
||||
values = [str(getattr(i, "identifier", "")) for i in items]
|
||||
if values:
|
||||
quoted = ", ".join(f'"{v}"' for v in values)
|
||||
return f"Literal[{quoted}]"
|
||||
return "str"
|
||||
|
||||
if ptype == "POINTER":
|
||||
fixed = getattr(prop, "fixed_type", None)
|
||||
if fixed is not None:
|
||||
return f"bpy.types.{getattr(fixed, 'identifier', 'object')} | None"
|
||||
return "object | None"
|
||||
|
||||
if ptype == "COLLECTION":
|
||||
return "object"
|
||||
|
||||
if ptype in ("FLOAT", "INT", "BOOLEAN") and is_array:
|
||||
base = _RAW_RNA_TYPE_MAP.get(ptype, "object")
|
||||
if ptype == "FLOAT" and subtype in _VECTOR_SUBTYPES:
|
||||
return "mathutils.Vector | collections.abc.Sequence[float]"
|
||||
if ptype == "FLOAT" and subtype == "EULER":
|
||||
return "mathutils.Euler | collections.abc.Sequence[float]"
|
||||
if (
|
||||
ptype == "FLOAT"
|
||||
and subtype in ("COLOR", "COLOR_GAMMA")
|
||||
and array_length == 3
|
||||
):
|
||||
return "mathutils.Color | collections.abc.Sequence[float]"
|
||||
if ptype == "FLOAT" and subtype == "MATRIX":
|
||||
return "mathutils.Matrix | collections.abc.Sequence[float]"
|
||||
return f"collections.abc.Sequence[{base}]"
|
||||
|
||||
return _RAW_RNA_TYPE_MAP.get(ptype, "object")
|
||||
|
||||
|
||||
def _rna_prop_default(prop: object) -> str:
|
||||
"""Extract the default value from an RNA property as a string for stubs."""
|
||||
ptype: str = getattr(prop, "type", "")
|
||||
is_array: bool = getattr(prop, "is_array", False)
|
||||
|
||||
try:
|
||||
if ptype == "ENUM":
|
||||
is_flag = getattr(prop, "is_enum_flag", False)
|
||||
if is_flag:
|
||||
# Enum flags are sets — use ellipsis since the type is Literal, not set
|
||||
return "..."
|
||||
val = str(getattr(prop, "default", ""))
|
||||
# If the default is not in the enum items, use ellipsis
|
||||
items = {
|
||||
str(getattr(i, "identifier", ""))
|
||||
for i in getattr(prop, "enum_items", [])
|
||||
}
|
||||
],
|
||||
if val and val in items:
|
||||
return repr(val)
|
||||
return "..."
|
||||
|
||||
if is_array:
|
||||
arr = getattr(prop, "default_array", None)
|
||||
if arr is not None:
|
||||
return repr(list(arr))
|
||||
return "..."
|
||||
|
||||
val = getattr(prop, "default", None)
|
||||
if val is None:
|
||||
return "None"
|
||||
return repr(val)
|
||||
except Exception:
|
||||
return "..."
|
||||
|
||||
|
||||
def _introspect_operator(op: object) -> FunctionData | None:
|
||||
"""Introspect a single bpy.ops operator and return its typed signature."""
|
||||
get_rna = getattr(op, "get_rna_type", None)
|
||||
if get_rna is None or not callable(get_rna):
|
||||
return None
|
||||
try:
|
||||
rna = get_rna()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
idname_fn = getattr(op, "idname_py", None)
|
||||
if idname_fn is None:
|
||||
return None
|
||||
try:
|
||||
py_name: str = idname_fn()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
# Extract the function name (e.g. "mesh.primitive_cube_add" -> "primitive_cube_add")
|
||||
func_name = py_name.split(".")[-1] if "." in py_name else py_name
|
||||
doc: str = getattr(rna, "description", "") or ""
|
||||
|
||||
# All operators accept an optional execution context as the first positional arg
|
||||
params: list[ParamData] = [
|
||||
{
|
||||
"name": "execution_context",
|
||||
"type": "Literal['INVOKE_DEFAULT', 'INVOKE_REGION_WIN', 'INVOKE_REGION_CHANNELS', 'INVOKE_REGION_PREVIEW', 'INVOKE_AREA', 'INVOKE_SCREEN', 'EXEC_DEFAULT', 'EXEC_REGION_WIN', 'EXEC_REGION_CHANNELS', 'EXEC_REGION_PREVIEW', 'EXEC_AREA', 'EXEC_SCREEN'] | None",
|
||||
"default": "None",
|
||||
"kind": "POSITIONAL_ONLY",
|
||||
},
|
||||
]
|
||||
for prop in getattr(rna, "properties", []):
|
||||
pid: str = getattr(prop, "identifier", "")
|
||||
if pid == "rna_type":
|
||||
continue
|
||||
param_type = _raw_rna_prop_to_type(prop)
|
||||
default = _rna_prop_default(prop)
|
||||
params.append(
|
||||
{
|
||||
"name": pid,
|
||||
"type": param_type,
|
||||
"default": default,
|
||||
"kind": "KEYWORD_ONLY",
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"name": func_name,
|
||||
"doc": doc,
|
||||
"params": params,
|
||||
"return_type": "set[str]",
|
||||
"is_classmethod": False,
|
||||
}
|
||||
|
||||
|
||||
def _build_ops_submodule_variables(submodule_names: list[str]) -> list[VariableData]:
|
||||
"""Build typed bpy.ops submodule variable declarations."""
|
||||
return [
|
||||
{"name": sub_name, "type": "_OpsSubModule", "value": "..."}
|
||||
for sub_name in submodule_names
|
||||
]
|
||||
def _introspect_ops_submodule(
|
||||
ops_mod: object, sub_name: str, op_base_name: str
|
||||
) -> tuple[StructData, list[StructData]]:
|
||||
"""Introspect an ops submodule.
|
||||
|
||||
Returns the module-level struct (_OpsModule_*) and a list of per-operator
|
||||
structs that inherit from the operator base class (e.g. BPyOpFunction).
|
||||
Each operator is a class with a typed __call__ so that both
|
||||
``bpy.ops.mesh.subdivide(number_cuts=3)`` and
|
||||
``bpy.ops.mesh.subdivide.poll()`` type-check correctly.
|
||||
"""
|
||||
sub = getattr(ops_mod, sub_name)
|
||||
op_structs: list[StructData] = []
|
||||
op_props: list[PropertyData] = []
|
||||
|
||||
for op_name in sorted(dir(sub)):
|
||||
if op_name.startswith("_"):
|
||||
continue
|
||||
op = getattr(sub, op_name, None)
|
||||
if op is None:
|
||||
continue
|
||||
func_data = _introspect_operator(op)
|
||||
if func_data is None:
|
||||
continue
|
||||
|
||||
# Create a per-operator class inheriting from the base operator type
|
||||
op_class_name = f"_Op_{sub_name}_{op_name}"
|
||||
call_method: FunctionData = {
|
||||
"name": "__call__",
|
||||
"doc": func_data["doc"],
|
||||
"params": func_data["params"],
|
||||
"return_type": "set[str]",
|
||||
"is_classmethod": False,
|
||||
}
|
||||
op_struct: StructData = {
|
||||
"name": op_class_name,
|
||||
"doc": func_data["doc"],
|
||||
"base": op_base_name,
|
||||
"properties": [],
|
||||
"methods": [call_method],
|
||||
}
|
||||
op_structs.append(op_struct)
|
||||
op_props.append(
|
||||
{
|
||||
"name": op_name,
|
||||
"type": op_class_name,
|
||||
"is_readonly": False,
|
||||
"description": func_data["doc"],
|
||||
}
|
||||
)
|
||||
|
||||
class_name = f"_OpsModule_{sub_name}"
|
||||
module_struct: StructData = {
|
||||
"name": class_name,
|
||||
"doc": f"Operators in bpy.ops.{sub_name}.",
|
||||
"base": None,
|
||||
"properties": op_props,
|
||||
"methods": [],
|
||||
}
|
||||
|
||||
return module_struct, op_structs
|
||||
|
||||
|
||||
def introspect_ops_module() -> ModuleData:
|
||||
@@ -1950,17 +2130,37 @@ def introspect_ops_module() -> ModuleData:
|
||||
|
||||
_apply_ops_method_return_fixups(op_struct, sample_op)
|
||||
_apply_ops_property_and_method_fixups(op_struct)
|
||||
_append_ops_call_method(op_struct)
|
||||
|
||||
sub_struct = _build_ops_submodule_struct(op_struct["name"])
|
||||
variables = _build_ops_submodule_variables(submodule_names)
|
||||
# Introspect each ops submodule with typed operator classes
|
||||
structs: list[StructData] = [op_struct]
|
||||
variables: list[VariableData] = []
|
||||
|
||||
print(" Introspecting bpy.ops operators...", file=sys.stderr, flush=True)
|
||||
total_ops = 0
|
||||
for sub_name in submodule_names:
|
||||
module_struct, per_op_structs = _introspect_ops_submodule(
|
||||
ops_mod, sub_name, op_struct["name"]
|
||||
)
|
||||
# Add per-operator classes first (they're referenced by the module struct)
|
||||
structs.extend(per_op_structs)
|
||||
structs.append(module_struct)
|
||||
total_ops += len(per_op_structs)
|
||||
variables.append(
|
||||
{"name": sub_name, "type": module_struct["name"], "value": "..."}
|
||||
)
|
||||
print(
|
||||
f" Introspected {total_ops} operators "
|
||||
+ f"in {len(submodule_names)} submodules",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
|
||||
return {
|
||||
"module": "bpy.ops",
|
||||
"doc": "Blender operator access.",
|
||||
"functions": [],
|
||||
"variables": variables,
|
||||
"structs": [op_struct, sub_struct],
|
||||
"structs": structs,
|
||||
}
|
||||
|
||||
|
||||
@@ -2531,12 +2731,29 @@ def _merge_missing_c_methods(
|
||||
structs: list[StructData], bpy_types_module: ModuleType
|
||||
) -> None:
|
||||
"""Add C-level methods missing from RNA metadata for each struct."""
|
||||
# Build parent method/property lookup for override detection
|
||||
struct_by_name = {s["name"]: s for s in structs}
|
||||
|
||||
def _get_all_parent_names(struct: StructData) -> set[str]:
|
||||
names: set[str] = set()
|
||||
base = struct.get("base")
|
||||
if base:
|
||||
# Strip generic params (e.g. "bpy_prop_collection[Object]" -> "bpy_prop_collection")
|
||||
base_name = base.split("[")[0]
|
||||
parent = struct_by_name.get(base_name)
|
||||
if parent:
|
||||
names |= {m["name"] for m in parent["methods"]}
|
||||
names |= {p["name"] for p in parent["properties"]}
|
||||
names |= _get_all_parent_names(parent)
|
||||
return names
|
||||
|
||||
for struct in structs:
|
||||
cls = getattr(bpy_types_module, struct["name"], None)
|
||||
if cls is None:
|
||||
continue
|
||||
existing = {m["name"] for m in struct["methods"]}
|
||||
existing |= {p["name"] for p in struct["properties"]}
|
||||
parent_names = _get_all_parent_names(struct)
|
||||
for attr_name in sorted(cls.__dict__):
|
||||
if attr_name.startswith("_") or attr_name in existing:
|
||||
continue
|
||||
@@ -2554,12 +2771,16 @@ def _merge_missing_c_methods(
|
||||
func_data = introspect_callable(bound, attr_name)
|
||||
if func_data:
|
||||
func_data["is_classmethod"] = True
|
||||
if attr_name in parent_names:
|
||||
func_data["is_override"] = True
|
||||
struct["methods"].append(func_data)
|
||||
elif raw_type in ("method_descriptor", "builtin_function_or_method"):
|
||||
obj = getattr(cls, attr_name)
|
||||
if callable(obj):
|
||||
func_data = introspect_callable(obj, attr_name)
|
||||
if func_data:
|
||||
if attr_name in parent_names:
|
||||
func_data["is_override"] = True
|
||||
struct["methods"].append(func_data)
|
||||
elif raw_type == "function":
|
||||
# Python functions with RST docstrings are API methods
|
||||
@@ -2568,6 +2789,8 @@ def _merge_missing_c_methods(
|
||||
if ":rtype:" in doc or ":type " in doc:
|
||||
func_data = introspect_callable(raw, attr_name)
|
||||
if func_data:
|
||||
if attr_name in parent_names:
|
||||
func_data["is_override"] = True
|
||||
struct["methods"].append(func_data)
|
||||
|
||||
|
||||
@@ -2738,6 +2961,53 @@ def introspect_rna_types() -> ModuleData:
|
||||
bpy_app = importlib.import_module("bpy.app")
|
||||
blender_version: tuple[int, ...] = getattr(bpy_app, "version", (0, 0, 0))
|
||||
temp_override = ctx.__class__.__dict__.get("temp_override")
|
||||
if temp_override is not None and blender_version < (4, 4, 0):
|
||||
# On Blender < 4.4, probing temp_override() hangs, but the docstring
|
||||
# still references ContextTempOverride. Generate a minimal stub.
|
||||
if "ContextTempOverride" not in known:
|
||||
stub: StructData = {
|
||||
"name": "ContextTempOverride",
|
||||
"doc": "Context manager for context overrides.",
|
||||
"base": None,
|
||||
"properties": [],
|
||||
"methods": [
|
||||
{
|
||||
"name": "__enter__",
|
||||
"doc": "",
|
||||
"params": [],
|
||||
"return_type": "Context",
|
||||
"is_classmethod": False,
|
||||
},
|
||||
{
|
||||
"name": "__exit__",
|
||||
"doc": "",
|
||||
"params": [
|
||||
{
|
||||
"name": "exc_type",
|
||||
"type": "object",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_OR_KEYWORD",
|
||||
},
|
||||
{
|
||||
"name": "exc_val",
|
||||
"type": "object",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_OR_KEYWORD",
|
||||
},
|
||||
{
|
||||
"name": "exc_tb",
|
||||
"type": "object",
|
||||
"default": None,
|
||||
"kind": "POSITIONAL_OR_KEYWORD",
|
||||
},
|
||||
],
|
||||
"return_type": "None",
|
||||
"is_classmethod": False,
|
||||
},
|
||||
],
|
||||
}
|
||||
structs.append(stub)
|
||||
known.add("ContextTempOverride")
|
||||
if (
|
||||
temp_override is not None
|
||||
and type(temp_override).__name__ == "method_descriptor"
|
||||
|
||||
Reference in New Issue
Block a user