Skip to content

Commit 04afc8f

Browse files
committed
State recorder is significantly more verbose now.
1 parent c797472 commit 04afc8f

File tree

2 files changed

+106
-15
lines changed

2 files changed

+106
-15
lines changed

src/pytribeam/GUI/state_recorder.py

Lines changed: 103 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,104 @@
33
import tkinter as tk
44
from tkinter import messagebox
55
import datetime
6+
from typing import Any, Set, List
67

78
from pytribeam import utilities
89
from pytribeam import types as tbt
910
from pytribeam import factory
1011
from pytribeam.GUI import CustomTkinterWidgets as ctk
1112

13+
import autoscript_sdb_microscope_client.structures as as_structs
14+
15+
16+
def _is_public_name(name: str) -> bool:
17+
"""Return ``True`` if *name* does not start with an underscore.
18+
19+
Hidden attributes (``_private`` or ``__dunder__``) are filtered out.
20+
"""
21+
return not name.startswith("_")
22+
23+
24+
def _collect(
25+
obj: Any,
26+
prefix: str,
27+
visited: Set[int],
28+
) -> List[str]:
29+
"""Recursive helper for :func:`collect_attribute_paths`.
30+
31+
Parameters
32+
----------
33+
obj:
34+
The current object being inspected.
35+
prefix:
36+
Dot-separated prefix representing the path to *obj*.
37+
visited:
38+
Set of ``id`` values already seen to prevent infinite loops.
39+
"""
40+
# Guard against circular references.
41+
obj_id = id(obj)
42+
if obj_id in visited:
43+
return []
44+
visited.add(obj_id)
45+
46+
results: List[str] = []
47+
for name in dir(obj):
48+
if not _is_public_name(name):
49+
continue
50+
try:
51+
attr = getattr(obj, name)
52+
except Exception:
53+
# Some descriptors may raise; skip them.
54+
continue
55+
56+
full_path = f"{prefix}.{name}" if prefix else name
57+
58+
if callable(attr):
59+
continue
60+
elif isinstance(attr, str) or isinstance(attr, bool) or isinstance(attr, int) or isinstance(attr, float) or isinstance(attr, list) or isinstance(attr, tuple) or isinstance(attr, dict):
61+
results.append((full_path, attr))
62+
elif isinstance(attr, as_structs.StagePosition):
63+
results.extend([
64+
(full_path + ".coordinate_system", attr.coordinate_system),
65+
(full_path + ".x", attr.x),
66+
(full_path + ".y", attr.y),
67+
(full_path + ".z", attr.z),
68+
(full_path + ".t", attr.t),
69+
(full_path + ".r", attr.r),
70+
])
71+
else:
72+
results.extend(_collect(attr, full_path, visited))
73+
74+
return results
75+
76+
77+
def collect_attribute_paths(obj: Any, name: str = None) -> List[str]:
78+
"""Return a list of dot-separated attribute paths for *obj*.
79+
80+
The function walks the public attribute tree of *obj* and records the path
81+
to every callable (function, method, built-in) it encounters. Sub-objects that
82+
are modules or classes are explored recursively. Private attributes (those
83+
beginning with an underscore) and non-callable values are omitted.
84+
85+
Parameters
86+
----------
87+
obj:
88+
The root Python object to introspect - typically a module.
89+
name:
90+
Optional explicit name for the root object. If omitted, ``obj``'s
91+
``__name__`` attribute (when present) is used; otherwise an empty prefix
92+
is assumed.
93+
94+
Returns
95+
-------
96+
List[str]
97+
A list of strings such as ``"pkg.f1"``, ``"pkg.submod.g2"``.
98+
"""
99+
root_name = name or getattr(obj, "__name__", "")
100+
# If the root has no useful name, start with an empty prefix.
101+
prefix = root_name if root_name else ""
102+
return _collect(obj, prefix, set())
103+
12104

13105
def get_microscope_state(host: str, port: int) -> dict:
14106
microscope = tbt.Microscope()
@@ -19,21 +111,17 @@ def get_microscope_state(host: str, port: int) -> dict:
19111
connection_port=None,
20112
)
21113

22-
beam = factory.active_beam_with_settings(microscope)
23-
detector = factory.active_detector_settings(microscope)
24-
image_settings = factory.active_image_settings(microscope)
25-
image_device = factory.active_imaging_device(microscope)
26-
scan = factory.active_scan_settings(microscope)
27-
position = factory.active_stage_position_settings(microscope)
28-
29-
beam = str(beam)
30-
detector = str(detector)
31-
image_settings = str(image_settings)
32-
image_device = str(image_device)
33-
scan = str(scan)
34-
position = str(position)
35-
36-
return dict(beam=beam, detector=detector, image_settings=image_settings, image_device=image_device, scan=scan, position=position)
114+
state = {}
115+
116+
for s in ["beams", "detector", "gas", "patterning", "specimen", "state", "vacuum", "imaging"]:
117+
state[s] = {k: i for (k, i) in collect_attribute_paths(getattr(microscope, s), "scope." + s)}
118+
119+
for q in [1, 2, 3, 4]:
120+
microscope.imaging.set_active_view(q)
121+
device = str(tbt.Device(microscope.imaging.get_active_device()))
122+
state["imaging"][f"scope.imaging.quad{q}.active_device"] = device
123+
124+
return state
37125

38126

39127
def ensure_file_exists():

src/pytribeam/types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ class Device(IntEnum):
696696
OPTICAL_MICROSCOPE = as_enums.ImagingDevice.OPTICAL_MICROSCOPE
697697
VOLUMESCOPE_APPROACH_CAMERA = as_enums.ImagingDevice.VOLUMESCOPE_APPROACH_CAMERA
698698

699+
def __str__(self):
700+
return self.name
701+
699702

700703
class DummyFile(object):
701704
"""

0 commit comments

Comments
 (0)