diff --git a/introspect.py b/introspect.py index 76a5ac8..2b5f76b 100644 --- a/introspect.py +++ b/introspect.py @@ -1433,25 +1433,15 @@ def _fix_dunder_signatures( def _is_getset_writable(cls: type[object], attr_name: str) -> bool: """Test if a C getset_descriptor property is writable. - C getset_descriptors that have a setter implement __set__. - Those without a setter raise AttributeError on __set__ calls. - We test this by checking if __set__ raises on a dummy call. + We check the docstring for "(read-only)" or "(readonly)" hints. + If no hint is found, assume writable (most C getset_descriptors are). """ descriptor = cls.__dict__.get(attr_name) if descriptor is None: return False - # If the descriptor doesn't implement __set__ at all, it's read-only - if not hasattr(descriptor, "__set__"): + doc = getattr(descriptor, "__doc__", "") or "" + if "read-only" in doc.lower() or "readonly" in doc.lower(): return False - # Try calling __set__ with None — a writable descriptor will attempt - # the set (and fail on None), while a read-only one raises AttributeError - try: - descriptor.__set__(None, None) - except AttributeError: - return False - except Exception: - # Any other error means __set__ exists (it just didn't like our args) - return True return True @@ -2720,20 +2710,22 @@ def introspect_rna_types() -> ModuleData: 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 + # Probe temp_override to discover ContextTempOverride. + # Skip on Blender < 4.4 where this call hangs. + 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 type(temp_override).__name__ == "method_descriptor" + and blender_version >= (4, 4, 0) + ): try: - result = func() + result = ctx.temp_override() 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) diff --git a/overrides/4.0/bpy.path.json b/overrides/4.0/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.0/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.0/gpu.state.json b/overrides/4.0/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.0/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.0/gpu.types.json b/overrides/4.0/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.0/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +} diff --git a/overrides/4.1/bpy.path.json b/overrides/4.1/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.1/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.1/gpu.state.json b/overrides/4.1/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.1/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.1/gpu.types.json b/overrides/4.1/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.1/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +} diff --git a/overrides/4.2/bpy.path.json b/overrides/4.2/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.2/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.2/gpu.state.json b/overrides/4.2/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.2/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.2/gpu.types.json b/overrides/4.2/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.2/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +} diff --git a/overrides/4.3/bpy.path.json b/overrides/4.3/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.3/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.3/gpu.state.json b/overrides/4.3/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.3/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.3/gpu.types.json b/overrides/4.3/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.3/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +} diff --git a/overrides/4.4/bpy.path.json b/overrides/4.4/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.4/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.4/gpu.state.json b/overrides/4.4/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.4/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.4/gpu.types.json b/overrides/4.4/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.4/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +} diff --git a/overrides/4.5/bpy.path.json b/overrides/4.5/bpy.path.json new file mode 100644 index 0000000..bc36764 --- /dev/null +++ b/overrides/4.5/bpy.path.json @@ -0,0 +1,22 @@ +{ + "abspath": { + "params": { + "path": "str | bytes" + } + }, + "basename": { + "params": { + "path": "str | bytes" + } + }, + "is_subdir": { + "params": { + "directory": "str | bytes" + } + }, + "native_pathsep": { + "params": { + "path": "str | bytes" + } + } +} diff --git a/overrides/4.5/gpu.state.json b/overrides/4.5/gpu.state.json new file mode 100644 index 0000000..63647e9 --- /dev/null +++ b/overrides/4.5/gpu.state.json @@ -0,0 +1,8 @@ +{ + "active_framebuffer_get": { + "return_type": "gpu.types.GPUFrameBuffer" + }, + "viewport_get": { + "return_type": "tuple[int, int, int, int]" + } +} diff --git a/overrides/4.5/gpu.types.json b/overrides/4.5/gpu.types.json new file mode 100644 index 0000000..cc0037f --- /dev/null +++ b/overrides/4.5/gpu.types.json @@ -0,0 +1,7 @@ +{ + "GPUShader.uniform_float": { + "params": { + "value": "float | int | Sequence[float] | mathutils.Matrix | mathutils.Vector | mathutils.Euler | mathutils.Quaternion | mathutils.Color" + } + } +}