33import tkinter as tk
44from tkinter import messagebox
55import datetime
6+ from typing import Any , Set , List
67
78from pytribeam import utilities
89from pytribeam import types as tbt
910from pytribeam import factory
1011from 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
13105def 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
39127def ensure_file_exists ():
0 commit comments