Skip to content

Commit dbe93d8

Browse files
committed
rename ScenePartStateApi -> SceneMutationApi and clean up docs
1 parent 3c1fed3 commit dbe93d8

7 files changed

Lines changed: 30 additions & 49 deletions

File tree

‎src/ansys/visor/viewer/app/trame/local_app.py‎

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,18 @@
2626
vtkObject.GlobalWarningDisplayOff()
2727

2828

29-
class ScenePartStateApi(Protocol):
29+
class SceneMutationApi(Protocol):
3030
"""Structural type of the coordinator surface LocalApp calls.
3131
3232
Typing only: there is no ``runtime_checkable`` decoration and no
3333
``isinstance`` check anywhere against it. Declaring it here rather than
3434
importing the scene keeps this module free of any scene type, so the
3535
injected object remains LocalApp's only route to the scene.
3636
37-
Not all of it is per-part, and the name is historical. ``sync_camera``,
38-
the three widget-state toggles and ``set_projection`` are scene-wide, and
39-
they are declared here anyway: the one production injection site passes
40-
the whole scene coordinator, so a second protocol would be the same object
41-
under a second name. Read this as the whole coordinator surface LocalApp calls, not only
42-
the per-part part of it.
37+
Covers both per-part mutations (visibility, opacity, colour, selection)
38+
and scene-wide ones (camera sync, the widget-state toggles, projection,
39+
cross-section plane). The one production injection site passes the
40+
whole scene coordinator, so this protocol describes that whole surface.
4341
"""
4442

4543
def set_part_visibility(self, node_id: int, visible: bool) -> None: ...
@@ -217,7 +215,7 @@ def __init__(
217215
standalone: bool = True,
218216
trame_logger: Logger | None = None,
219217
pick_geometry=None,
220-
scene_part_state_api: ScenePartStateApi | None = None,
218+
scene_mutation_api: SceneMutationApi | None = None,
221219
):
222220
self.server = server
223221
# Callable to get the scene details in JSON format
@@ -226,10 +224,10 @@ def __init__(
226224
self._handle_save_state_response = handle_save_state_response
227225
# Callable for sub-geometry picking (optional)
228226
self._pick_geometry = pick_geometry
229-
# Per-part visual state coordinator (see ScenePartStateApi). The one
227+
# Per-part visual state coordinator (see SceneMutationApi). The one
230228
# production construction site always supplies it; it is optional so
231229
# that the class stays constructible without a scene.
232-
self._scene_part_state_api = scene_part_state_api
230+
self._scene_mutation_api = scene_mutation_api
233231
# logger for logging trame server lifecycle info
234232
self.__trame_logger = trame_logger
235233

@@ -354,13 +352,13 @@ def perf_report_server_update(self, payload: dict):
354352
# body.
355353
# ------------------------------------------------------------------
356354

357-
def _part_state_api(self, trigger_name: str, payload: BaseModel) -> ScenePartStateApi | None:
355+
def _part_state_api(self, trigger_name: str, payload: BaseModel) -> SceneMutationApi | None:
358356
"""Return the injected coordinator, or ``None`` after logging."""
359357
logger.debug("[trigger] %s arrived: %s.", trigger_name, payload)
360-
if self._scene_part_state_api is None:
358+
if self._scene_mutation_api is None:
361359
logger.debug("%s: no scene part-state API injected; ignoring.", trigger_name)
362360
return None
363-
return self._scene_part_state_api
361+
return self._scene_mutation_api
364362

365363
@trigger("set_part_visibility")
366364
@parse_payload(SetPartVisibilityPayload)
@@ -492,31 +490,14 @@ def sync_camera(self, payload) -> None:
492490
# ------------------------------------------------------------------
493491
# Widget-state triggers
494492
#
495-
# Frontend -> Backend. One trigger per server-tracked toggle. Each
496-
# carries the absolute target value the client's widget settled on,
497-
# never a toggle and never a delta: the toolbar buttons are toggles, so
498-
# the client reads its widget back after the local write and sends the
499-
# result. A message the client suppresses as redundant is therefore
500-
# indistinguishable from one that set a value the server already held,
501-
# and both are correct.
493+
# Frontend -> Backend. One trigger per server-tracked toggle. Each
494+
# carries the absolute target value, not a delta, so a redundant
495+
# message is indistinguishable from a no-op one, and both are fine.
496+
# No ``origin`` field: unlike the camera, a toggle echo is idempotent.
502497
#
503-
# No ``origin`` field (RS-1). The camera needed one because a
504-
# programmatic echo re-applied a *stale* camera over a newer one; a
505-
# toggle echo carries the same boolean the server already holds, so the
506-
# write is idempotent and the client's own widgets damp it with their
507-
# value guards. It is the same echo the per-part deliveries already
508-
# produce on load. Separating delivery from mutation is a later story's
509-
# work, not this one's.
510-
#
511-
# Payloads are validated at this boundary by ``@parse_payload`` exactly
512-
# as the per-part ones are. The wire key is ``visible`` on the three
513-
# visibility triggers and ``parallel`` on ``set_projection``; none carries
514-
# a pydantic alias, snake_case and camelCase coinciding on all four.
515-
#
516-
# ``set_projection`` sits in this block because it arrives from the same
517-
# toolbar and under the same absolute-value rule, but it is not a fourth
518-
# toggle: the server keeps no projection field, the camera record holds
519-
# it, and the coordinator re-serialises the camera as part of the write.
498+
# ``set_projection`` lives here too: it is delivered the same way, but
499+
# it writes the camera record's projection field rather than a toggle
500+
# of its own.
520501
# ------------------------------------------------------------------
521502

522503
@trigger("set_cross_section_visibility")

‎src/ansys/visor/viewer/app/visor_vtk_local.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ def _initialize_rendering(self, standalone: bool, trame_log_dir: str | None) ->
5252
world_x,
5353
world_y,
5454
world_z: self._scene.pick_geometry(actor_wasm_id, cell_id, mode, world_x, world_y, world_z),
55-
# The scene satisfies LocalApp's ScenePartStateApi protocol
55+
# The scene satisfies LocalApp's SceneMutationApi protocol
5656
# structurally: the six per-part coordinator methods carry exactly
5757
# the names and signatures the triggers call.
58-
scene_part_state_api=self._scene,
58+
scene_mutation_api=self._scene,
5959
)
6060

‎tests/unit/app/test_local_app.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def mock_server():
9797
@pytest.fixture
9898
def api():
9999
"""Stand-in for the injected per-part coordinator object."""
100-
return MagicMock(name="scene_part_state_api")
100+
return MagicMock(name="scene_mutation_api")
101101

102102

103103
@pytest.fixture
@@ -108,7 +108,7 @@ def app(mock_server, api):
108108
get_scene_details_json=MagicMock(),
109109
handle_save_state_response=MagicMock(),
110110
standalone=True,
111-
scene_part_state_api=api,
111+
scene_mutation_api=api,
112112
)
113113

114114

‎tests/unit/app/test_local_app_set_projection.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def mock_server():
7272
@pytest.fixture
7373
def api():
7474
"""Stand-in for the injected scene coordinator."""
75-
return MagicMock(name="scene_part_state_api")
75+
return MagicMock(name="scene_mutation_api")
7676

7777

7878
@pytest.fixture
@@ -83,7 +83,7 @@ def app(mock_server, api):
8383
get_scene_details_json=MagicMock(),
8484
handle_save_state_response=MagicMock(),
8585
standalone=True,
86-
scene_part_state_api=api,
86+
scene_mutation_api=api,
8787
)
8888

8989

‎tests/unit/app/test_local_app_sync_camera.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def mock_server():
9191
@pytest.fixture
9292
def api():
9393
"""Stand-in for the injected scene coordinator."""
94-
return MagicMock(name="scene_part_state_api")
94+
return MagicMock(name="scene_mutation_api")
9595

9696

9797
@pytest.fixture
@@ -102,7 +102,7 @@ def app(mock_server, api):
102102
get_scene_details_json=MagicMock(),
103103
handle_save_state_response=MagicMock(),
104104
standalone=True,
105-
scene_part_state_api=api,
105+
scene_mutation_api=api,
106106
)
107107

108108

‎tests/unit/app/test_local_app_widget_triggers.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def mock_server():
6868
@pytest.fixture
6969
def api():
7070
"""Stand-in for the injected scene coordinator."""
71-
return MagicMock(name="scene_part_state_api")
71+
return MagicMock(name="scene_mutation_api")
7272

7373

7474
@pytest.fixture
@@ -79,7 +79,7 @@ def app(mock_server, api):
7979
get_scene_details_json=MagicMock(),
8080
handle_save_state_response=MagicMock(),
8181
standalone=True,
82-
scene_part_state_api=api,
82+
scene_mutation_api=api,
8383
)
8484

8585

‎tests/unit/app/test_visor_vtk_local.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -560,8 +560,8 @@ def test_local_app_receives_the_scene_as_the_part_state_api(local_app_call):
560560
"""The scene itself is injected, not a wrapper or a set of lambdas."""
561561
call, scene, instance = local_app_call
562562

563-
assert call.kwargs["scene_part_state_api"] is scene
564-
assert call.kwargs["scene_part_state_api"] is instance._scene
563+
assert call.kwargs["scene_mutation_api"] is scene
564+
assert call.kwargs["scene_mutation_api"] is instance._scene
565565

566566

567567
def test_local_app_still_receives_the_pre_existing_arguments(local_app_call):

0 commit comments

Comments
 (0)