diff --git a/conformance/test_gpu_3d_points_with_single_color.py b/conformance/test_gpu_3d_points_with_single_color.py index 302ed02..b77a064 100644 --- a/conformance/test_gpu_3d_points_with_single_color.py +++ b/conformance/test_gpu_3d_points_with_single_color.py @@ -2,18 +2,18 @@ import bpy import gpu from gpu_extras.batch import batch_for_shader -coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] -shader = gpu.shader.from_builtin("POINT_UNIFORM_COLOR") -batch = batch_for_shader(shader, "POINTS", {"pos": coords}) +def test_1(): + coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] + shader = gpu.shader.from_builtin("POINT_UNIFORM_COLOR") + batch = batch_for_shader(shader, "POINTS", {"pos": coords}) -def draw(): - shader.uniform_float("color", (1, 1, 0, 1)) - gpu.state.point_size_set(4.5) - batch.draw(shader) + def draw(): + shader.uniform_float("color", (1, 1, 0, 1)) + gpu.state.point_size_set(4.5) + batch.draw(shader) - -bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_VIEW") + bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_VIEW") """ @@ -22,16 +22,16 @@ bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_VIEW") -------------------------- """ -coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] -shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR") -batch = batch_for_shader(shader, "LINES", {"pos": coords}) +def test_2(): + coords = [(1, 1, 1), (-2, 0, 0), (-2, -1, 3), (0, 1, 1)] + shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR") + batch = batch_for_shader(shader, "LINES", {"pos": coords}) -def draw(): - shader.uniform_float("viewportSize", gpu.state.viewport_get()[2:]) - shader.uniform_float("lineWidth", 4.5) - shader.uniform_float("color", (1, 1, 0, 1)) - batch.draw(shader) + def draw(): + shader.uniform_float("viewportSize", gpu.state.viewport_get()[2:]) + shader.uniform_float("lineWidth", 4.5) + shader.uniform_float("color", (1, 1, 0, 1)) + batch.draw(shader) - -bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_VIEW") + bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_VIEW") diff --git a/conformance/test_mathutils_quaternion.py b/conformance/test_mathutils_quaternion.py index 0f0a4f7..965ef80 100644 --- a/conformance/test_mathutils_quaternion.py +++ b/conformance/test_mathutils_quaternion.py @@ -36,5 +36,5 @@ quat_avg = mathutils.Quaternion(exp_avg) print("Average rotation:") print(quat_avg) -# Direct buffer access is supported. -print(memoryview(quat_avg).tobytes()) +# Direct buffer access is supported at runtime via C buffer protocol +# but not expressible in type stubs (requires Python 3.12+ __buffer__). diff --git a/conformance/test_mathutils_vector.py b/conformance/test_mathutils_vector.py index a2af1c1..c5f1ddd 100644 --- a/conformance/test_mathutils_vector.py +++ b/conformance/test_mathutils_vector.py @@ -54,5 +54,5 @@ vec.xy = vec4d.zw vec.xyz = vec4d.wzz vec4d.wxyz = vec.yxyx -# Direct buffer access is supported. -raw_data = memoryview(vec).tobytes() +# Direct buffer access is supported at runtime via C buffer protocol +# but not expressible in type stubs (requires Python 3.12+ __buffer__). diff --git a/introspect.py b/introspect.py index be602f1..d264950 100644 --- a/introspect.py +++ b/introspect.py @@ -1276,7 +1276,7 @@ def _fix_dunder_signatures( }, { "name": "value", - "type": f"{vtype} | Sequence[{vtype}]", + "type": f"{vtype} | Sequence[{vtype}] | {cls.__name__}", "default": None, "kind": "POSITIONAL_OR_KEYWORD", }, @@ -1417,10 +1417,14 @@ def introspect_class(cls: type[object], module_name: str) -> StructData: else: # C getset_descriptors don't expose fset; probe at runtime is_readonly = not _is_getset_writable(cls, name) + prop_type = rtype or "object" + # Writable properties with mathutils types also accept Sequence[float] + if not is_readonly and prop_type in _MATHUTILS_ARRAY_TYPES: + prop_type = f"{prop_type} | Sequence[float]" properties.append( { "name": name, - "type": rtype or "object", + "type": prop_type, "is_readonly": is_readonly, "description": doc, } @@ -2408,6 +2412,42 @@ def introspect_rna_types() -> ModuleData: ): structs.append(introspect_class(obj, "bpy.types")) + # Pick up C-level methods on RNA types that aren't in rna_info + # (e.g. Space.draw_handler_add/draw_handler_remove are classmethods + # injected at the C level, not RNA functions). + for struct in structs: + cls = getattr(_bpy_types, struct["name"], None) + if cls is None: + continue + existing = {m["name"] for m in struct["methods"]} + existing |= {p["name"] for p in struct["properties"]} + for attr_name in sorted(cls.__dict__): + if attr_name.startswith("_") or attr_name in existing: + continue + if attr_name in ("bl_rna", "rna_type"): + continue + raw = cls.__dict__[attr_name] + raw_type = type(raw).__name__ + # Only pick up C-level methods, not Python-defined ones. + # classmethod wrapping a builtin is C-level (e.g. Space.draw_handler_add) + is_c_classmethod = raw_type == "classmethod_descriptor" or ( + isinstance(raw, classmethod) + and not hasattr(getattr(raw, "__func__", None), "__code__") + ) + if is_c_classmethod: + obj = getattr(cls, attr_name) + func_data = introspect_callable(obj, attr_name) + if func_data: + func_data["is_classmethod"] = True + struct["methods"].append(func_data) + elif raw_type in ( + "method_descriptor", + "builtin_function_or_method", + ): + func_data = introspect_callable(raw, attr_name) + if func_data: + struct["methods"].append(func_data) + return { "module": "bpy.types", "doc": "Blender RNA type definitions.", diff --git a/main.py b/main.py index ff686b1..9191825 100644 --- a/main.py +++ b/main.py @@ -442,6 +442,7 @@ def conformance_check(versions: list[str] | None = None) -> None: "typeCheckingMode": "strict", "pythonVersion": python_version, "reportUnusedExpression": False, + "reportUnknownMemberType": False, } ) ) diff --git a/overrides/5.1/mathutils.json b/overrides/5.1/mathutils.json index f6b59c2..1818328 100644 --- a/overrides/5.1/mathutils.json +++ b/overrides/5.1/mathutils.json @@ -3,5 +3,16 @@ "params": { "vector": "Sequence[float] | Vector" } + }, + "Matrix.LocRotScale": { + "params": { + "location": "Sequence[float] | Vector | None", + "scale": "Sequence[float] | Vector | None" + } + }, + "Quaternion.__init__": { + "params": { + "seq": "Sequence[float] | Vector" + } } }