From 1c8fad3c1364f44fecc301c1bba4bef44a911da3 Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Wed, 27 May 2026 13:26:21 +0200 Subject: [PATCH] Fix tool.Parametric to ship safely on v0.8.0 bim layer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three corrective fixes folded into one commit. All surface as addon-load / save-time exceptions on v0.8.0's bim layer because PR2's tool.Parametric refactor over-committed to the PR4 contract. 1. iter_gizmo_preference_classes — the previous implementation returned only the shared GizmoPreferencesFeature class. v0.8.0's bim/ui.py declares PointerProperty fields ('door', 'window', ...) on GizmoPreferences that point at per-feature GizmoPreferences classes; those must be registered BEFORE GizmoPreferences itself. The shared-class-only return broke addon registration with: 'door' PointerProperty could not register (see previous error) Restore the v0.8.0 per-feature lookup (iterate EDIT_TYPES, look up each GizmoPreferences on ui_module) and keep the shared-class lookup as forward-compat. Tag FIXME(PR5). 2. EDIT_TYPES — drop the array / pipe_segment / duct_segment entries from the registry. Their bim.finish_editing_ operators land with PR4. Registering them in PR2's EDIT_TYPES without the operators makes auto-commit-on-save dispatch a non-existent finish_op for any object whose BIMProperties.is_editing flag is True, raising: RuntimeError: 'bim.finish_editing_array' must be a registered tool.Ifc.Operator subclass for undo-safe IFC mutation PR4 re-adds the three entries together with their operators. Tag FIXME(PR4). 3. tool.Blender.Modifier shim block — upgrade the prose comment to a formal FIXME(PR5) marker so the PR5 cleanup sweep finds it via grep alongside every other tagged shim site. Generated with the assistance of an AI coding tool. --- src/bonsai/bonsai/tool/blender.py | 8 +++---- src/bonsai/bonsai/tool/parametric.py | 33 ++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 40c5059563..b0c9423906 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -1329,10 +1329,10 @@ class Blender(bonsai.core.tool.Blender): class Modifier: # ---------------------------------------------------------------------- - # Backward-compat shims for callers still using the pre-refactor API. - # The is_ predicates now live on tool.Parametric; the Array helper - # bag now lives on tool.Array. PR4 migrates each caller; these shims - # are removed in PR5's cleanup. + # FIXME(PR5): backward-compat shims for callers still using the + # pre-refactor API. The is_ predicates now live on tool.Parametric; + # the Array helper bag now lives on tool.Array. PR4 migrates each caller; + # this whole shim block is removed in PR5's cleanup. # ---------------------------------------------------------------------- @classmethod diff --git a/src/bonsai/bonsai/tool/parametric.py b/src/bonsai/bonsai/tool/parametric.py index 594352c449..0460379273 100644 --- a/src/bonsai/bonsai/tool/parametric.py +++ b/src/bonsai/bonsai/tool/parametric.py @@ -147,6 +147,11 @@ class Parametric(bonsai.core.tool.Parametric): self._data.clear() self._gen = None + # FIXME(PR4): array / pipe_segment / duct_segment land with their + # finish/cancel operators in PR4. Adding them to EDIT_TYPES without those + # operators makes auto-commit-on-save dispatch bim.finish_editing_ + # for objects flagged as in-edit, which then raises because the operator + # doesn't exist. PR4 re-adds the three entries together with the operators. EDIT_TYPES: list[ParametricObject] = [ ParametricObject("door", has_non_editable_path=True, supports_build_edit_lifecycle=True), ParametricObject("window", has_non_editable_path=True, supports_build_edit_lifecycle=True), @@ -154,9 +159,6 @@ class Parametric(bonsai.core.tool.Parametric): ParametricObject("railing", supports_build_edit_lifecycle=True), ParametricObject("roof", supports_build_edit_lifecycle=True), ParametricObject("wall"), - ParametricObject("array", supports_build_edit_lifecycle=True), - ParametricObject("pipe_segment", has_non_editable_path=True, supports_build_edit_lifecycle=True), - ParametricObject("duct_segment", has_non_editable_path=True, supports_build_edit_lifecycle=True), ] # Annotations for the uppercase constants populated from ``EDIT_TYPES`` by @@ -168,9 +170,6 @@ class Parametric(bonsai.core.tool.Parametric): RAILING: ClassVar[ParametricObject] ROOF: ClassVar[ParametricObject] WALL: ClassVar[ParametricObject] - ARRAY: ClassVar[ParametricObject] - PIPE_SEGMENT: ClassVar[ParametricObject] - DUCT_SEGMENT: ClassVar[ParametricObject] _geom_generation: int = 0 @@ -389,10 +388,26 @@ class Parametric(bonsai.core.tool.Parametric): @classmethod def iter_gizmo_preference_classes(cls, ui_module) -> list[type]: - """Shared ``GizmoPreferencesFeature`` class as a one-element list, or - empty if absent. Must register before ``GizmoPreferences``.""" + """``GizmoPreferences`` classes that exist on ``ui_module`` for + every registry entry, plus the shared ``GizmoPreferencesFeature`` if + present. Order matches ``EDIT_TYPES``. Used by ``bim/__init__.py`` to + inject the per-type ``GizmoPreferences`` classes at the correct + point — before ``ui.GizmoPreferences``, which references them via + ``PointerProperty``.""" + # FIXME(PR5): drop the per-feature loop once PR4 consolidates + # bim/ui.py to use a single shared GizmoPreferencesFeature class + # and rewrites GizmoPreferences accordingly. The shared-class + # branch is the forward-compat path; the per-feature loop keeps + # v0.8.0's bim/ui.py working until then. + out: list[type] = [] + for feature in cls.EDIT_TYPES: + gpref = getattr(ui_module, f"GizmoPreferences{feature.name.capitalize()}", None) + if gpref is not None: + out.append(gpref) shared = getattr(ui_module, "GizmoPreferencesFeature", None) - return [shared] if shared is not None else [] + if shared is not None: + out.append(shared) + return out # --- Feature-kind predicates ------------------------------------------------ # One predicate per registered parametric type. Each is total: accepts any