mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Consolidate load_post parametric drains
bim/handler.py was importing two feature-module internals (wall_offset_gizmos.clear_caches, preview_base.discard_pending_previews) to drain load-transient parametric state alongside the existing tool.Parametric.heal_stale_edit_flags() call inside _apply_save_file_invariants. Each new parametric drain added one top-level import and one inline call — every load_post drain leaked into handler.py's namespace. Hide all three drains behind tool.Parametric.on_load_post(scene), sited adjacent to heal_stale_edit_flags. The two feature-module imports become late imports inside on_load_post — same pattern as refresh_post_commit's existing `import bonsai.bim.handler` — which sidesteps the tool.parametric -> bim.module.model.preview_base -> bonsai.tool registration-time cycle. The forward-compat AST contract that pinned "every module-scope GenerationKeyedCache + clear_caches MUST be drained on load_post" follows the call site to its new home — the test now walks tool.Parametric.on_load_post instead of _apply_save_file_invariants. No behaviour change. 45/45 affected bim tests pass (test_handler_forward_compat, test_preview_base, test_wall_offset_gizmos, test_parametric_registry). ruff + black clean on all touched files. Generated with the assistance of an AI coding tool.
This commit is contained in:
@@ -41,7 +41,6 @@ from bonsai.bim.decorator_cache import (
|
||||
from bonsai.bim.ifc import IfcStore, get_cache_or_detect_lock
|
||||
from bonsai.bim.module.aggregate.decorator import AggregateDecorator
|
||||
from bonsai.bim.module.georeference.decorator import GeoreferenceDecorator
|
||||
from bonsai.bim.module.model import wall_offset_gizmos
|
||||
from bonsai.bim.module.model.array import (
|
||||
ArrayPreviewDecorator,
|
||||
ArraySelectionHighlightDecorator,
|
||||
@@ -53,7 +52,6 @@ from bonsai.bim.module.model.decorator import (
|
||||
WallAxisDecorator,
|
||||
WallFilletPreviewDecorator,
|
||||
)
|
||||
from bonsai.bim.module.model.preview_base import discard_pending_previews
|
||||
from bonsai.bim.module.model.wall import WallGizmoPreviewDecorator
|
||||
from bonsai.bim.module.nest.decorator import NestDecorator
|
||||
|
||||
@@ -436,8 +434,8 @@ def subscribe_to_viewport_shading_changes():
|
||||
|
||||
def _apply_save_file_invariants(scene: bpy.types.Scene) -> None:
|
||||
"""Invariants enforced on every load_post: msgbus subscription, IFC owner
|
||||
settings, scene-bound caches, draft-flag healing, multi-instance lock probe,
|
||||
and previews discarded so saved preview state never resurfaces on reopen."""
|
||||
settings, scene-bound caches, load-transient parametric state, and the
|
||||
multi-instance lock probe."""
|
||||
global global_subscription_owner
|
||||
active_object_key = bpy.types.LayerObjects, "active"
|
||||
bpy.msgbus.subscribe_rna(
|
||||
@@ -448,9 +446,7 @@ def _apply_save_file_invariants(scene: bpy.types.Scene) -> None:
|
||||
ifcopenshell.api.owner.settings.get_application = get_application
|
||||
AuthoringData.type_thumbnails = {}
|
||||
|
||||
tool.Parametric.heal_stale_edit_flags()
|
||||
discard_pending_previews(scene)
|
||||
wall_offset_gizmos.clear_caches()
|
||||
tool.Parametric.on_load_post(scene)
|
||||
|
||||
if tool.Ifc.get() and bpy.data.is_saved:
|
||||
props = tool.Blender.get_bim_props()
|
||||
|
||||
@@ -271,6 +271,18 @@ class Parametric(bonsai.core.tool.Parametric):
|
||||
for obj in bpy.data.objects:
|
||||
cls._validated_editing_feature(obj)
|
||||
|
||||
@classmethod
|
||||
def on_load_post(cls, scene: bpy.types.Scene) -> None:
|
||||
"""Drain load-transient parametric state on a freshly opened scene
|
||||
so no draft edit flag, preview flag, or cache entry persists from
|
||||
the saved file."""
|
||||
from bonsai.bim.module.model import wall_offset_gizmos
|
||||
from bonsai.bim.module.model.preview_base import discard_pending_previews
|
||||
|
||||
cls.heal_stale_edit_flags()
|
||||
discard_pending_previews(scene)
|
||||
wall_offset_gizmos.clear_caches()
|
||||
|
||||
@classmethod
|
||||
def get_pending_edits(cls) -> list[tuple[bpy.types.Object, str]]:
|
||||
"""``(object, finish_operator_bl_idname)`` pairs for every object
|
||||
|
||||
@@ -146,7 +146,7 @@ def _modules_with_module_scope_cache_and_clear():
|
||||
yield path.stem
|
||||
|
||||
|
||||
def test_apply_save_file_invariants_drains_every_module_scope_geom_cache(handler_tree: ast.Module) -> None:
|
||||
def test_on_load_post_drains_every_module_scope_geom_cache() -> None:
|
||||
"""Module-scope ``GenerationKeyedCache`` instances persist across file
|
||||
loads — the counter they invalidate against is class-level and survives
|
||||
a ``.blend`` reload. Without a ``load_post`` drain the cache may serve
|
||||
@@ -154,9 +154,10 @@ def test_apply_save_file_invariants_drains_every_module_scope_geom_cache(handler
|
||||
freed ``bpy.data``, raising ``ReferenceError`` on the next attribute read.
|
||||
|
||||
Pin: every model module that exposes both a module-scope cache and a
|
||||
top-level ``clear_caches`` is called from ``_apply_save_file_invariants``,
|
||||
top-level ``clear_caches`` is called from ``tool.Parametric.on_load_post``,
|
||||
the central post-load drain."""
|
||||
fn = _function_node(handler_tree, "_apply_save_file_invariants")
|
||||
parametric_tree = ast.parse(PARAMETRIC_PATH.read_text(encoding="utf-8"))
|
||||
fn = _function_node(parametric_tree, "on_load_post")
|
||||
drained: set[str] = set()
|
||||
for node in ast.walk(fn):
|
||||
if (
|
||||
@@ -170,7 +171,7 @@ def test_apply_save_file_invariants_drains_every_module_scope_geom_cache(handler
|
||||
if missing:
|
||||
pytest.fail(
|
||||
"Module(s) expose a module-scope GenerationKeyedCache + clear_caches() but "
|
||||
f"_apply_save_file_invariants does not drain them on load_post: {sorted(missing)}. "
|
||||
f"tool.Parametric.on_load_post does not drain them on load_post: {sorted(missing)}. "
|
||||
"Add a `<module>.clear_caches()` call so freshly-loaded files cannot serve "
|
||||
"entries holding freed bpy.data references from the previous file."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user