diff --git a/eco/devices_general/digitizers.py b/eco/devices_general/digitizers.py index 2e0ee14..08d601b 100644 --- a/eco/devices_general/digitizers.py +++ b/eco/devices_general/digitizers.py @@ -145,7 +145,7 @@ class DigitizerIoxosBoxcarChannel(Assembly): is_display=False, is_status=True, ) - self.status_collection.append(self.waveform_slow, force=True) + self.status_collection.append(self.waveform_slow) self._append( DetectorPvDataStream, self.pvbase + ":BOXCAR.VALH", diff --git a/eco/devices_general/motors.py b/eco/devices_general/motors.py index 2725b72..1f3ece4 100755 --- a/eco/devices_general/motors.py +++ b/eco/devices_general/motors.py @@ -449,7 +449,7 @@ class PshellMotor(Assembly): self.name_pshell = name_pshell self.robot = robot self.pc = self.robot.pc - self.settings_collection.append(self, force=True) + self.status_collection.append(self, selection="settings") self._append( AdjustableFS, f"/sf/bernina/config/eco/reference_values/robot_{name}_limit_high.json", @@ -1589,7 +1589,7 @@ class SmaractRecord(Assembly): ): super().__init__(name=name) # self.settings.append(self) - self.settings_collection.append(self, force=True) + self.status_collection.append(self, selection="settings") self.pvname = pvname self._motor = _Motor(pvname) diff --git a/eco/elements/assembly.py b/eco/elements/assembly.py index 968d8e0..2a1c929 100644 --- a/eco/elements/assembly.py +++ b/eco/elements/assembly.py @@ -4,6 +4,7 @@ from inspect import isclass import json from pathlib import Path from tkinter import W +import weakref from markdown import markdown from numpy import isin @@ -43,9 +44,9 @@ class StatusCollection: def get_list(self, selection=None): ls = [] for item in self._list: - if item is self: + if item == self: continue - if item is self.parent: + if item == self.parent: continue recurse = True item_name = item.alias.get_full_name(base=self.parent) @@ -58,7 +59,7 @@ class StatusCollection: item.__dict__[self.name], self.__class__ ): if recurse: - for titem in item.__dict__[self.name].get_list(): + for titem in item.__dict__[self.name].get_list(selection=selection): if titem not in ls: ls.append(titem) else: @@ -77,14 +78,19 @@ class StatusCollection: if obj not in self._list: self._list.append(obj) - def remove(self, obj): + def remove(self, obj, selection=None): + """Remove an object from the collection. If selection is given, only remove from that selection.""" if obj in self._list: obj_name = obj.alias.get_full_name(base=self.parent) - self._list.remove(obj) + if selection is None: + self._list.remove(obj) else: raise ValueError("Item not in list") - - for selection in self.selections: + if selection is not None: + selections = [selection] + else: + selections = self.selections.keys() + for selection in selections: if obj_name in self.selections[selection]: del self.selections[selection][obj_name] @@ -255,8 +261,12 @@ class Assembly: self.__dict__[name], selection="settings", recursive=True ) if is_display: + if isinstance(is_display, str): + recursive = is_display.lower() == "recursive" + else: + recursive = False self.status_collection.append( - self.__dict__[name], selection="display", recursive=is_display + self.__dict__[name], selection="display", recursive=recursive ) def get_status( @@ -438,13 +448,13 @@ class Assembly: typechar += "✏️" elif is_detector: typechar += "👁️" - if hasattr(to, "settings_collection"): + if hasattr(to, "status_collection"): typechar += " ↳" try: value = to.get_current_value() except AttributeError: - if hasattr(to, "settings_collection"): + if hasattr(to, "status_collection"): value = "\x1b[3mhas lower level items\x1b[0m" if isinstance(value, Enum): diff --git a/eco/fel/swissfel.py b/eco/fel/swissfel.py index f77f8f0..d105282 100644 --- a/eco/fel/swissfel.py +++ b/eco/fel/swissfel.py @@ -70,7 +70,7 @@ class SwissFel(Assembly): self._append( AdjustablePvEnum, "SAROP-ARAMIS:BEAMLINE", - pvname_set = "SAROP-ARAMIS:BEAMLINE_SP", + pvname_set="SAROP-ARAMIS:BEAMLINE_SP", name="aramis_beamline_switch", is_display=True, is_setting=True, @@ -241,7 +241,9 @@ class MessageBoard(Assembly): name="cristallina_status", is_setting=True, ) - self._append(Message, "SF-OP:ESC-MSG", name="cristallina_message", is_setting=True) + self._append( + Message, "SF-OP:ESC-MSG", name="cristallina_message", is_setting=True + ) self._append( AdjustablePvEnum, "SF-OP:ESE-MSG:STATUS", @@ -330,7 +332,7 @@ class UndulatorK(Assembly): is_display=False, ) self.gaps.append(self.__dict__[f"und{undno:02d}_gap"]) - self.settings_collection.append(self) + self.status_collection.append(self, selection="settings") self.unit = self.aramis_undulator_photon_energy.unit def calc_new_Ksets(self, energy_target, energy_start=None): @@ -353,18 +355,17 @@ class UndulatorK(Assembly): start_time = time.time() for kset, val in zip(self.ksets, vals): kset.set_target_value(val) - - - + sleep(0.2) for gap in self.gaps: while gap.get_change_done() == 0: sleep(0.02) - if (time.time()-start_time) > 10: - print('NB: did not see all Undulators start move and stop for 10s, calling move done anyways.') + if (time.time() - start_time) > 10: + print( + "NB: did not see all Undulators start move and stop for 10s, calling move done anyways." + ) break sleep(1) - def set_target_value(self, value, hold=False): return Changer( diff --git a/eco/timing/lasertiming_edwin.py b/eco/timing/lasertiming_edwin.py index d62490a..ddde597 100644 --- a/eco/timing/lasertiming_edwin.py +++ b/eco/timing/lasertiming_edwin.py @@ -174,7 +174,7 @@ from ..elements.assembly import Assembly class XltEpics(Assembly): def __init__(self, pvname="SLAAR02-LTIM-PDLY", name="lxt_epics"): super().__init__(name=name) - self.settings_collection.append(self, force=True) + self.status_collection.append(self, selection="settings") self.pvname = pvname # self.settings_collection.append(self, force=True) # self.status_collection.append(self, force=True) @@ -339,7 +339,7 @@ class XltEpics(Assembly): class LaserRateControl(Assembly): def __init__(self, pvname="SLAAR02-LTIM-PDLY", name=None): super().__init__(name=name) - self.settings_collection.append(self, force=True) + self.status_collection.append(self, selection="settings") self.pvname = pvname # self.settings_collection.append(self, force=True) # self.status_collection.append(self, force=True) diff --git a/eco/utilities/config.py b/eco/utilities/config.py index 0d0ceab..3fbdcf2 100644 --- a/eco/utilities/config.py +++ b/eco/utilities/config.py @@ -1,3 +1,4 @@ +import io import json import importlib from pathlib import Path @@ -543,6 +544,20 @@ class Namespace(Assembly): else: if hasattr(self, "exc_init"): self.exc_init.shutdown(wait=False) + + # class TeeTextIO(io.TextIOBase): + # def __init__(self, target): + # self.target = target + # self.stringio = io.StringIO() + + # def write(self, s): + # writecount = self.target.write(s) + # self.stringio.write(s[:writecount]) + # return writecount + + # stdout = sys.stdout + # sys.stdout = TeeTextIO(sys.stdout) + with ThreadPoolExecutor(max_workers=max_workers) as exc: list( progress.track( @@ -575,6 +590,10 @@ class Namespace(Assembly): ) # ) # # ) + + # output = sys.stdout.stringio.getvalue() + # sys.stdout = stdout + if giveup_failed: failed_names = names_to_init.intersection(self.lazy_names) for k in failed_names: diff --git a/eco/xdiagnostics/profile_monitors.py b/eco/xdiagnostics/profile_monitors.py index e508f47..c718086 100755 --- a/eco/xdiagnostics/profile_monitors.py +++ b/eco/xdiagnostics/profile_monitors.py @@ -159,8 +159,7 @@ class ProfKbBernina(Assembly): self._append( MotorRecord, pvname_zoom, name="zoom", is_setting=True, is_display=True ) - ix = self.zoom.settings_collection._list.index(self.zoom.offset) - self.zoom.settings_collection._list.pop(ix) + self.zoom.status_collection.remove(self.zoom.offset, selection="settings") def movein_keep_target(self, wait=False): ch = self.mirror_in.set_target_value(1) diff --git a/eco/xoptics/dcm_new.py b/eco/xoptics/dcm_new.py index 438faa9..36347f1 100644 --- a/eco/xoptics/dcm_new.py +++ b/eco/xoptics/dcm_new.py @@ -19,6 +19,7 @@ from ..devices_general.utilities import Changer from ..elements.assembly import Assembly from eco.xoptics.dcm_pathlength_compensation import MonoTimecompensation + @get_from_archive @spec_convenience @update_changes @@ -64,7 +65,9 @@ class DoubleCrystalMono(Assembly): self._append(DcmConfig, self.pvname, name="mono_config") - self._append(AdjustablePvEnum, pvname + ":BRAGG_ACCURACY_SP", name="theta_accuracy") + self._append( + AdjustablePvEnum, pvname + ":BRAGG_ACCURACY_SP", name="theta_accuracy" + ) self._append(AdjustablePvEnum, pvname + ":HOLDING_BRAGG_SP", name="theta_hold") self._append( @@ -72,21 +75,18 @@ class DoubleCrystalMono(Assembly): pvname + ":RX12", name="theta", is_setting=True, - view_toplevel_only=True, ) self._append( MotorRecord, pvname + ":TX12", name="x", is_setting=True, - view_toplevel_only=True, ) self._append( MotorRecord, pvname + ":T2", name="gap", is_setting=True, - view_toplevel_only=True, ) self._append( MotorRecord, @@ -94,7 +94,6 @@ class DoubleCrystalMono(Assembly): name="roll1", is_setting=True, has_park_pv=True, - view_toplevel_only=True, ) self._append( AdjustablePv, @@ -102,14 +101,12 @@ class DoubleCrystalMono(Assembly): pvreadbackname=pvname + ":PIEZO1_VOLTAGE", name="roll1_piezo", is_setting=True, - view_toplevel_only=True, ) self._append( MotorRecord, pvname + ":RZ2", name="roll2", is_setting=True, - view_toplevel_only=True, ) self._append( MotorRecord, @@ -117,7 +114,6 @@ class DoubleCrystalMono(Assembly): name="pitch2", is_setting=True, has_park_pv=True, - view_toplevel_only=True, ) self._append( AdjustablePv, @@ -125,7 +121,6 @@ class DoubleCrystalMono(Assembly): pvreadbackname=pvname + ":PIEZO2_VOLTAGE", name="pitch2_piezo", is_setting=True, - view_toplevel_only=True, ) self._append( AdjustablePv, @@ -200,9 +195,9 @@ class DoubleCrystalMono(Assembly): ) if feedback_enable: - self._append(AdjustablePvEnum,feedback_enable,name="feedback_enabled") + self._append(AdjustablePvEnum, feedback_enable, name="feedback_enabled") if feedback_message: - self._append(DetectorPvString,feedback_message,name="feedback_message") + self._append(DetectorPvString, feedback_message, name="feedback_message") def add_mono_und_calibration_point(self): mono_energy = self.energy.get_current_value() @@ -232,15 +227,14 @@ class DoubleCrystalMono(Assembly): self.energy._pvreadback.remove_callback(index) else: self.energy._pvreadback.clear_callbacks() - + def feedback_start(self): self.pitch2.parked(1) self.roll1.parked(1) self.feedback_enabled(1) - + def feedback_stop(self): self.feedback_enabled(0) - class DcmConfig(Assembly):