diff --git a/pyproject.toml b/pyproject.toml index 2bd6b6c3ea..e5dc3d25c5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ select = [ "RUF015", # next() > list_comprehension[0] "RUF022", # sort __all__ "I", # import sorting + "unused-noqa", ] ignore = [ "FA100", # Conflicts with Blender using annotations for props definitions. diff --git a/src/bonsai/bonsai/bim/module/clip_box/face_quad.py b/src/bonsai/bonsai/bim/module/clip_box/face_quad.py index 70639881d5..193c1104ee 100644 --- a/src/bonsai/bonsai/bim/module/clip_box/face_quad.py +++ b/src/bonsai/bonsai/bim/module/clip_box/face_quad.py @@ -516,7 +516,7 @@ def _world_segment_to_screen_pixels( # --------------------------------------------------------------------------- -class BIM_GT_box_face_quad(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname convention +class BIM_GT_box_face_quad(bpy.types.Gizmo): """Near-invisible face-quad click target with drag-to-resize modal. Geometry: a unit quad in the local XY plane at z=0. The adapter @@ -620,7 +620,7 @@ class BIM_GT_box_face_quad(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname return {"RUNNING_MODAL"} -class BIM_GT_box_face_outline(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname convention +class BIM_GT_box_face_outline(bpy.types.Gizmo): """Thin non-interactive colored edge outline for one face. Drawn as 4 line segments in the face plane. The layout helper diff --git a/src/bonsai/bonsai/bim/module/clip_box/gizmos.py b/src/bonsai/bonsai/bim/module/clip_box/gizmos.py index 24d72f7b5c..e4ee1cfa64 100644 --- a/src/bonsai/bonsai/bim/module/clip_box/gizmos.py +++ b/src/bonsai/bonsai/bim/module/clip_box/gizmos.py @@ -160,7 +160,7 @@ def _make_face_set_cb(gz: Any, group: Any, axis: int, is_max: bool): return setter -class OBJECT_GGT_bim_clip_box(bpy.types.GizmoGroup): # noqa: N801 — Blender bl_idname convention +class OBJECT_GGT_bim_clip_box(bpy.types.GizmoGroup): """Face-quad resize handles on the active clip box. Renders six near-invisible click-target quads and six colored edge diff --git a/src/bonsai/bonsai/bim/module/drawing/gizmos.py b/src/bonsai/bonsai/bim/module/drawing/gizmos.py index 53a4c8328e..17a86d3d04 100644 --- a/src/bonsai/bonsai/bim/module/drawing/gizmos.py +++ b/src/bonsai/bonsai/bim/module/drawing/gizmos.py @@ -5660,7 +5660,7 @@ class BaseParametricGizmoGroup: """ return 0.0 - def _update_view_dependent_dimensions(self, context: bpy.types.Context, mw: Matrix, props) -> None: # noqa: ARG002 + def _update_view_dependent_dimensions(self, context: bpy.types.Context, mw: Matrix, props) -> None: """Update overall_width, overall_height, and lining_offset based on view direction. This base implementation handles the common pattern for door/window gizmos. @@ -5837,7 +5837,7 @@ class BaseParametricGizmoGroup: self.update_dimension_gizmos(mw, props) self._refresh_element_specific(context, mw, props) - def _refresh_element_specific(self, context: bpy.types.Context, mw: "Matrix", props) -> None: # noqa: ARG002 + def _refresh_element_specific(self, context: bpy.types.Context, mw: "Matrix", props) -> None: """Override for element-specific refresh logic. Called from both refresh() (on state change) and draw_prepare() (per frame), @@ -6344,7 +6344,7 @@ class BaseParametricGizmoGroup: """ return (0.0, 0.0) - def get_icon_y_offset(self, context: bpy.types.Context, mw: Matrix) -> float: # noqa: ARG002 + def get_icon_y_offset(self, context: bpy.types.Context, mw: Matrix) -> float: """Get Y offset for icons based on view direction. Uses get_icon_y_extent() to determine how far to offset icons based on @@ -6546,9 +6546,7 @@ class BaseParametricGizmoGroup: self._refresh_element_specific(context, mw, props) - def _update_dimension_gizmo_positions( - self, context: bpy.types.Context, mw: "Matrix", props # noqa: ARG002 - ) -> None: + def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw: "Matrix", props) -> None: """Update dimension gizmo positions based on view direction. Override this method in subclasses to implement view-dependent diff --git a/src/bonsai/bonsai/bim/module/model/door.py b/src/bonsai/bonsai/bim/module/model/door.py index ba27524007..5041f5045b 100644 --- a/src/bonsai/bonsai/bim/module/model/door.py +++ b/src/bonsai/bonsai/bim/module/model/door.py @@ -560,7 +560,7 @@ class AddDoor(bpy.types.Operator, tool.Ifc.Operator): ) update_door_modifier_representation(obj) - def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002 + def _execute(self, context: bpy.types.Context) -> set[str]: for obj in tool.Blender.get_selected_objects(): if not tool.Blender.Modifier.is_eligible_for_door_modifier(obj): continue @@ -638,7 +638,7 @@ class RemoveDoor(bpy.types.Operator, tool.Ifc.Operator): pset = tool.Pset.get_element_pset(element, "BBIM_Door") ifcopenshell.api.pset.remove_pset(tool.Ifc.get(), product=element, pset=pset) - def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002 + def _execute(self, context: bpy.types.Context) -> set[str]: for obj in tool.Blender.get_selected_objects(): self.remove_door_on_object(obj) return {"FINISHED"} @@ -683,7 +683,7 @@ class ToggleDoorSwing(bpy.types.Operator, tool.Ifc.Operator): return True return False - def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002 + def _execute(self, context: bpy.types.Context) -> set[str]: obj = tool.Blender.get_active_object() if not obj: return {"CANCELLED"} @@ -909,9 +909,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): setattr(self, f"gizmo_swing_arc_{cfg.name}", main) setattr(self, f"gizmo_swing_arc_{cfg.name}_flip", flip) - def _refresh_element_specific( - self, context: bpy.types.Context, mw: Matrix, props: "BIMDoorProperties" # noqa: ARG002 - ) -> None: + def _refresh_element_specific(self, context: bpy.types.Context, mw: Matrix, props: "BIMDoorProperties") -> None: """Update door-specific swing arc gizmos.""" self.update_swing_gizmos(mw, props) diff --git a/src/bonsai/bonsai/bim/module/model/roof.py b/src/bonsai/bonsai/bim/module/model/roof.py index 823f95a8e1..f4835a7829 100644 --- a/src/bonsai/bonsai/bim/module/model/roof.py +++ b/src/bonsai/bonsai/bim/module/model/roof.py @@ -765,7 +765,7 @@ class GizmoRoofEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): def is_element_type(cls, element: ifcopenshell.entity_instance) -> bool: return tool.Parametric.is_roof(element) - def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw, props) -> None: # noqa: ARG002 + def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw, props) -> None: """Anchor every dimension gizmo at the object origin. Each gizmo's declared axis (height/slope along +Z, thickness along -Z) separates them in 3D so they don't visually collide despite sharing a @@ -776,7 +776,7 @@ class GizmoRoofEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): self.set_dimension_gizmo_position("angle", mw, origin, (0, 0, 1)) self.set_dimension_gizmo_position("roof_thickness", mw, origin, (0, 0, -1)) - def get_element_height(self, props) -> float: # noqa: ARG002 + def get_element_height(self, props) -> float: """Object-local Z of the mesh's topmost vertex, so the pen / validate / cancel / cycle row anchors visibly above sloped or stepped roof bodies rather than at the parametric ``props.height`` which may not diff --git a/src/bonsai/bonsai/bim/module/model/stair.py b/src/bonsai/bonsai/bim/module/model/stair.py index 70295d6e72..e13c823f6f 100644 --- a/src/bonsai/bonsai/bim/module/model/stair.py +++ b/src/bonsai/bonsai/bim/module/model/stair.py @@ -405,7 +405,7 @@ class SetStairTreads(bpy.types.Operator): bl_label = "Set Number of Treads" bl_options = {"REGISTER", "UNDO", "INTERNAL"} - def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: # noqa: ARG002 + def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: obj = context.active_object if not obj: return {"CANCELLED"} @@ -658,9 +658,7 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): self.tread_count_label_gizmo.alpha = 0.8 self.tread_count_label_gizmo.target_set_operator("bim.input_stair_treads") - def _refresh_element_specific( - self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties" # noqa: ARG002 - ) -> None: + def _refresh_element_specific(self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties") -> None: """Update stair-specific lock and tread count gizmos. Lock positioning is handled per-frame in the dimension-positioning hook.""" self.update_lock_gizmo(props) @@ -707,7 +705,7 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): self.update_gizmo_visibility(self.tread_count_label_gizmo, props.is_editing) def _update_dimension_gizmo_positions( - self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties" # noqa: ARG002 + self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties" ) -> None: """Update dimension gizmo positions based on camera view direction.""" viewing_from_negative_y, viewing_from_negative_x = self._frame_view_dir diff --git a/src/bonsai/bonsai/bim/module/model/wall.py b/src/bonsai/bonsai/bim/module/model/wall.py index 5b73f5641b..a70997774d 100644 --- a/src/bonsai/bonsai/bim/module/model/wall.py +++ b/src/bonsai/bonsai/bim/module/model/wall.py @@ -2174,7 +2174,7 @@ class GizmoWallEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup): return (far, near) def _update_dimension_gizmo_positions( - self, context: bpy.types.Context, mw: Matrix, props: "BIMWallProperties" # noqa: ARG002 + self, context: bpy.types.Context, mw: Matrix, props: "BIMWallProperties" ) -> None: """Re-position length / height / height_end dimensions to the camera-facing Y-side of the wall every frame. Mirrors the door & stair pattern: when the @@ -2530,7 +2530,7 @@ def _perpendicular_wall_params( return clamped_x, abs(cursor_local_y), side_sign -def _commit_pending_wall_edits_for_selection(context: bpy.types.Context) -> None: # noqa: ARG001 +def _commit_pending_wall_edits_for_selection(context: bpy.types.Context) -> None: """Thin wall-scoped alias for ``tool.Parametric.commit_pending_edits_for_selection``. Encapsulates the ``names=("wall",)`` filter so the registry name is diff --git a/src/bonsai/bonsai/bim/module/model/window.py b/src/bonsai/bonsai/bim/module/model/window.py index 5b470fc8e5..0ba1631d41 100644 --- a/src/bonsai/bonsai/bim/module/model/window.py +++ b/src/bonsai/bonsai/bim/module/model/window.py @@ -538,7 +538,7 @@ class RemoveWindow(bpy.types.Operator, tool.Ifc.Operator): bl_label = "Remove Window" bl_options = {"REGISTER"} - def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002 + def _execute(self, context: bpy.types.Context) -> set[str]: obj = context.active_object assert obj element = tool.Ifc.get_entity(obj) diff --git a/src/bonsai/bonsai/bim/parametric_lifecycle.py b/src/bonsai/bonsai/bim/parametric_lifecycle.py index 015a183377..832de66afc 100644 --- a/src/bonsai/bonsai/bim/parametric_lifecycle.py +++ b/src/bonsai/bonsai/bim/parametric_lifecycle.py @@ -558,7 +558,7 @@ class IntegerInputDialogMixin: return None return props - def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: # noqa: ARG002 + def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: props = self._resolve_props(context) if props is None: return {"CANCELLED"} diff --git a/src/bonsai/test/bim/module/drawing/test_gizmos.py b/src/bonsai/test/bim/module/drawing/test_gizmos.py index 18f640549b..c373ddfe42 100644 --- a/src/bonsai/test/bim/module/drawing/test_gizmos.py +++ b/src/bonsai/test/bim/module/drawing/test_gizmos.py @@ -45,14 +45,14 @@ def test_text_formatter_defaults_to_none(): def test_text_formatter_field_stores_callable(): - formatter = lambda props, value: f"{value:.2f}m" # noqa: E731 + formatter = lambda props, value: f"{value:.2f}m" config = DimensionGizmoConfig(attr_name="length", axis=(1, 0, 0), text_formatter=formatter) assert config.text_formatter is not None assert callable(config.text_formatter) def test_text_formatter_receives_props_and_value(): - formatter = lambda props, value: f"{props.label}={value}" # noqa: E731 + formatter = lambda props, value: f"{props.label}={value}" config = DimensionGizmoConfig(attr_name="length", axis=(1, 0, 0), text_formatter=formatter) props = SimpleNamespace(label="L") assert config.text_formatter(props, 3.14) == "L=3.14" diff --git a/src/bonsai/test/bim/module/model/test_transform_modal_gate.py b/src/bonsai/test/bim/module/model/test_transform_modal_gate.py index 139af4cdc0..3f55e6ea7a 100644 --- a/src/bonsai/test/bim/module/model/test_transform_modal_gate.py +++ b/src/bonsai/test/bim/module/model/test_transform_modal_gate.py @@ -104,7 +104,7 @@ class TestParametricGizmoPollsHideDuringTransformModal: continue try: result = poll(bpy.context) - except Exception as exc: # noqa: BLE001 + except Exception as exc: offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}")) continue if result: diff --git a/src/bonsai/test/bim/module/model/test_wall_gizmo_poll_gate.py b/src/bonsai/test/bim/module/model/test_wall_gizmo_poll_gate.py index 048b04c54b..ff3508cc32 100644 --- a/src/bonsai/test/bim/module/model/test_wall_gizmo_poll_gate.py +++ b/src/bonsai/test/bim/module/model/test_wall_gizmo_poll_gate.py @@ -98,7 +98,7 @@ class TestWallGizmoGroupsHideDuringPreview: continue try: result = poll(bpy.context) - except Exception as exc: # noqa: BLE001 + except Exception as exc: offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}")) continue if result: diff --git a/src/bonsai/test/bim/module/model/test_wall_gizmos_array_children.py b/src/bonsai/test/bim/module/model/test_wall_gizmos_array_children.py index 81f5ef5b15..96b62ed627 100644 --- a/src/bonsai/test/bim/module/model/test_wall_gizmos_array_children.py +++ b/src/bonsai/test/bim/module/model/test_wall_gizmos_array_children.py @@ -119,7 +119,7 @@ class TestWallGizmoGroupsHideOnArrayChildSelection: for name, cls in groups: try: result = cls.poll(bpy.context) - except Exception as exc: # noqa: BLE001 + except Exception as exc: offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}")) continue if result: @@ -159,7 +159,7 @@ class TestWallOperatorsRejectArrayChildSelection: for name, cls in ops: try: result = cls.poll(bpy.context) - except Exception as exc: # noqa: BLE001 + except Exception as exc: offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}")) continue if result: diff --git a/src/ifcmcp/ifcmcp/__main__.py b/src/ifcmcp/ifcmcp/__main__.py index da3f1deab7..5e90580567 100644 --- a/src/ifcmcp/ifcmcp/__main__.py +++ b/src/ifcmcp/ifcmcp/__main__.py @@ -1,5 +1,6 @@ # This file was generated with the assistance of an AI coding tool. import argparse +import importlib.util from ifcmcp import __version__ @@ -27,9 +28,7 @@ def main(): args = parser.parse_args() - try: - from mcp.server.fastmcp import FastMCP # noqa: F401 - except ImportError: + if importlib.util.find_spec("mcp.server.fastmcp") is None: import sys print( diff --git a/src/ifcmcp/ifcmcp/core.py b/src/ifcmcp/ifcmcp/core.py index a5a44bb26e..3f759607f3 100644 --- a/src/ifcmcp/ifcmcp/core.py +++ b/src/ifcmcp/ifcmcp/core.py @@ -3,7 +3,7 @@ from __future__ import annotations # inside ifcmcp/core.py import json -from collections.abc import Callable # noqa: F401 — Callable used in helpers below +from collections.abc import Callable from dataclasses import dataclass from typing import Any diff --git a/src/ifcopenshell-python/ifcopenshell/util/scripts/sync_stub.py b/src/ifcopenshell-python/ifcopenshell/util/scripts/sync_stub.py index 02ca02dece..891c2a3fe0 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/scripts/sync_stub.py +++ b/src/ifcopenshell-python/ifcopenshell/util/scripts/sync_stub.py @@ -81,7 +81,7 @@ from pathlib import Path from typing import Optional, Union sys.path.insert(0, str(Path(__file__).parent)) -from validate_stub import SubnameType, get_function_node_name, get_names_tree # noqa: E402 +from validate_stub import SubnameType, get_function_node_name, get_names_tree LICENSE_HEADER_START = "# IfcOpenShell - IFC toolkit and geometry engine" diff --git a/src/ifcquery/tests/test_plot.py b/src/ifcquery/tests/test_plot.py index 4c003ab946..a71b2cd909 100644 --- a/src/ifcquery/tests/test_plot.py +++ b/src/ifcquery/tests/test_plot.py @@ -1,6 +1,7 @@ from __future__ import annotations import base64 +import importlib.util import os import subprocess import sys @@ -19,19 +20,9 @@ import pytest from ifcquery.plot import _highlight_css_from_ids, plot -try: - import ifcopenshell.draw # noqa: F401 +HAS_DRAW = importlib.util.find_spec("ifcopenshell.draw") is not None - HAS_DRAW = True -except ImportError: - HAS_DRAW = False - -try: - import cairosvg # noqa: F401 - - HAS_CAIROSVG = True -except ImportError: - HAS_CAIROSVG = False +HAS_CAIROSVG = importlib.util.find_spec("cairosvg") is not None pytestmark = pytest.mark.skipif(not HAS_DRAW, reason="ifcopenshell.draw not available") diff --git a/src/ifcquery/tests/test_render.py b/src/ifcquery/tests/test_render.py index 28d83a6b68..6ba786b375 100644 --- a/src/ifcquery/tests/test_render.py +++ b/src/ifcquery/tests/test_render.py @@ -20,7 +20,7 @@ import pytest from ifcquery.render import _make_profile_occurrence, _make_type_occurrence, render try: - import pyvista # noqa: F401 + import pyvista HAS_PYVISTA = True except ImportError: