From 819b6f3f39ead91fd949932ccbe650d0b268d75b Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 24 Jan 2025 15:02:41 -0300 Subject: [PATCH 1/3] UTILS.WIP: add methods for saving/restoring machine state in meas experiments --- apsuite/utils.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/apsuite/utils.py b/apsuite/utils.py index 897db1ce..0b3be7c7 100644 --- a/apsuite/utils.py +++ b/apsuite/utils.py @@ -153,6 +153,29 @@ def wait_for_connection(self, timeout=None): return False return True + def get_devices_state(self): + """.""" + devs = self.devices + return self.get_equipaments_state(devs) + + def get_pvs_state(self): + """.""" + pvs = self.pvs + return self.get_equipaments_state(pvs) + + def get_equipaments_state(self, equipaments): + """.""" + equipaments_state = dict() + for name, equip in equipaments.items(): + state = { + attr: getattr(equip, attr) for attr in dir(equip) if + ( + not attr.startswith("_") + and not callable(getattr(equip, attr)) + ) + } + equipaments_state[name] = state + return equipaments_state class ThreadedMeasBaseClass(MeasBaseClass): """.""" @@ -203,3 +226,11 @@ def _run(self): if self._target is not None: self._target() self._finished.set() + + def _initialize(self): + """To be run before measurement. Save devices/pc initial state.""" + return NotImplementedError + + def _finish(self): + """To be run after measurement. Restore initial state.""" + return NotImplementedError From 347552c2265cf969f5a5454942a56301d877dc85 Mon Sep 17 00:00:00 2001 From: Matheus Velloso Date: Mon, 27 Jan 2025 14:15:00 -0300 Subject: [PATCH 2/3] UTILS.WIP: save/restore machine methods --- apsuite/utils.py | 93 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 27 deletions(-) diff --git a/apsuite/utils.py b/apsuite/utils.py index 0b3be7c7..cf73c3be 100644 --- a/apsuite/utils.py +++ b/apsuite/utils.py @@ -1,6 +1,7 @@ """.""" import logging as _log import sys as _sys +import os as _os from copy import deepcopy as _dcopy from threading import Event as _Event @@ -153,29 +154,75 @@ def wait_for_connection(self, timeout=None): return False return True - def get_devices_state(self): + def _get_equipments_state(self, equipments: dict): """.""" - devs = self.devices - return self.get_equipaments_state(devs) + equipments_state = dict() + for name, equip in equipments.items(): + state = _dcopy(equip.__dict__) + equipments_state[name] = state + return equipments_state - def get_pvs_state(self): + def get_machine_state(self): """.""" - pvs = self.pvs - return self.get_equipaments_state(pvs) + if not self.isonline: + return + devs_state = self._get_equipments_state(self.devices) + pvs_state = self._get_equipments_state(self.pvs) + machine_state = {"devices": devs_state, + "pvs" : pvs_state} + return machine_state + + def save_machine_state(self, fname): + """.""" + state = self.get_machine_state() + _save(data=state, fname=fname, overwrite=False) - def get_equipaments_state(self, equipaments): + def set_machine_state(self, machine_state): + """.""" + if not self.isonline: + print("Failed. Not online.") + return + + for key, entries in machine_state.items(): + if key == "devices": + equipments = self.devices + elif key == "pvs": + equipments = self.pvs + else: + raise ValueError(f"Unexpected key in saved_dict: {key}") + # Update attributes for each device or PV + for equip_name, attributes in entries.items(): + equipment = equipments[equip_name] # Retrieve device/PV + for attr_name, attr_value in attributes.items(): + setattr(equipment, attr_name, attr_value) + + def compare_states(self, state1, state2): """.""" - equipaments_state = dict() - for name, equip in equipaments.items(): - state = { - attr: getattr(equip, attr) for attr in dir(equip) if - ( - not attr.startswith("_") - and not callable(getattr(equip, attr)) - ) - } - equipaments_state[name] = state - return equipaments_state + if state1 == state2: + return True + # TODO: if not equal, return the diff + raise NotImplementedError + + def _finish(self, fname): + try: + init_state = _load(fname) + except FileNotFoundError: + print(f"File {fname} does not exist.") + except Exception as e: + print(f"An unexpected error occurred: {e}") + current_state = self.get_machine_state() + res = self.compare_states(current_state, init_state) + if not res: + print("Restoring init state.") + self.set_machine_state(init_state) + # TODO: wait and checking methods + try: + _os.remove(fname) + print(f"File '{fname}' successfully deleted.") + except OSError as e: + print(f"Error: {e.strerror} - Unable to delete file '{fname}'.") + return + class ThreadedMeasBaseClass(MeasBaseClass): """.""" @@ -225,12 +272,4 @@ def wait_measurement(self, timeout=None): def _run(self): if self._target is not None: self._target() - self._finished.set() - - def _initialize(self): - """To be run before measurement. Save devices/pc initial state.""" - return NotImplementedError - - def _finish(self): - """To be run after measurement. Restore initial state.""" - return NotImplementedError + self._finished.set() \ No newline at end of file From c25927445c10dfa3e36ecb1a71e5bede96a74fac Mon Sep 17 00:00:00 2001 From: Matheus Date: Tue, 28 Jan 2025 08:39:49 -0300 Subject: [PATCH 3/3] UTILS.ENH: changes during online tests --- apsuite/utils.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/apsuite/utils.py b/apsuite/utils.py index cf73c3be..c91a7077 100644 --- a/apsuite/utils.py +++ b/apsuite/utils.py @@ -154,11 +154,17 @@ def wait_for_connection(self, timeout=None): return False return True - def _get_equipments_state(self, equipments: dict): + def _get_equipments_state(self, equipments): """.""" equipments_state = dict() for name, equip in equipments.items(): - state = _dcopy(equip.__dict__) + state = { + attr: getattr(equip, attr) for attr in dir(equip) if + ( + not attr.startswith("_") + and not callable(getattr(equip, attr)) + ) + } equipments_state[name] = state return equipments_state @@ -194,7 +200,11 @@ def set_machine_state(self, machine_state): for equip_name, attributes in entries.items(): equipment = equipments[equip_name] # Retrieve device/PV for attr_name, attr_value in attributes.items(): - setattr(equipment, attr_name, attr_value) + try: + setattr(equipment, attr_name, attr_value) + except AttributeError: + # no writing access PV + pass def compare_states(self, state1, state2): """.""" @@ -272,4 +282,4 @@ def wait_measurement(self, timeout=None): def _run(self): if self._target is not None: self._target() - self._finished.set() \ No newline at end of file + self._finished.set()