refactor(flomni): consolidate global-var params into _GlobalVarParam descriptor

Replace 11 identical global-var-backed getter/setter property pairs with a
single _GlobalVarParam descriptor. Behavior is unchanged: same keys, defaults,
and None-handling; stitch_x/stitch_y retain int enforcement via the descriptor's
type_ guard (typeguard.check_type). Net -57 lines with no functional change.
This commit is contained in:
x12sa
2026-07-12 07:28:10 +02:00
committed by holler
co-authored by holler
parent 4fe8d02ba0
commit 01f74ea4f7
@@ -14,7 +14,7 @@ from bec_lib.alarm_handler import AlarmBase
from bec_lib.endpoints import MessageEndpoints
from bec_lib.pdf_writer import PDFWriter
from bec_lib.scan_repeat import scan_repeat
from typeguard import typechecked
from typeguard import check_type, typechecked
from csaxs_bec.bec_ipython_client.plugins.cSAXS import cSAXSBeamlineChecks
from csaxs_bec.bec_ipython_client.plugins.flomni.flomni_optics_mixin import FlomniOpticsMixin
@@ -1673,6 +1673,50 @@ class _TomoQueueProxy:
return self._load()[index]
class _GlobalVarParam:
"""Descriptor for a Flomni parameter backed by a BEC global variable.
Consolidates the boilerplate getter/setter pairs that read from and write
to the BEC global-var store. The value persists across BEC client restarts
(instance attributes do not), and is readable from other client sessions
via ``client.get_global_var(<name>)``.
The global-var key is taken from the attribute name the descriptor is
assigned to (see :meth:`__set_name__`), so it always matches the property
name -- exactly the invariant the hand-written pairs relied on.
Parameters
----------
default
Value returned by the getter when the global var is unset (``None``).
type_
Optional expected type. When given, the setter validates ``val`` with
:func:`typeguard.check_type` before storing, reproducing the
``@typechecked`` guard that previously wrapped some setters (raising
``TypeCheckError`` on a mismatch).
"""
def __init__(self, default, type_=None):
self._default = default
self._type = type_
def __set_name__(self, owner, name):
self._key = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
val = obj.client.get_global_var(self._key)
if val is None:
return self._default
return val
def __set__(self, obj, val):
if self._type is not None:
check_type(val, self._type)
obj.client.set_global_var(self._key, val)
class Flomni(
FlomniInitStagesMixin,
FlomniSampleTransferMixin,
@@ -1910,38 +1954,11 @@ class Flomni(
raise TypeError(f"progress must be a dict, got {type(val).__name__!r}")
self._progress_proxy._save(val)
@property
def tomo_shellstep(self):
val = self.client.get_global_var("tomo_shellstep")
if val is None:
return 1
return val
tomo_shellstep = _GlobalVarParam(1)
@tomo_shellstep.setter
def tomo_shellstep(self, val: float):
self.client.set_global_var("tomo_shellstep", val)
tomo_countingtime = _GlobalVarParam(0.1)
@property
def tomo_countingtime(self):
val = self.client.get_global_var("tomo_countingtime")
if val is None:
return 0.1
return val
@tomo_countingtime.setter
def tomo_countingtime(self, val: float):
self.client.set_global_var("tomo_countingtime", val)
@property
def manual_shift_y(self):
val = self.client.get_global_var("manual_shift_y")
if val is None:
return 0.0
return val
@manual_shift_y.setter
def manual_shift_y(self, val: float):
self.client.set_global_var("manual_shift_y", val)
manual_shift_y = _GlobalVarParam(0.0)
@property
def single_point_random_shift_max(self):
@@ -2009,40 +2026,11 @@ class Flomni(
else:
raise ValueError("Unknown tomo_type.")
@property
def corridor_size(self):
val = self.client.get_global_var("corridor_size")
if val is None:
val = -1
return val
corridor_size = _GlobalVarParam(-1)
@corridor_size.setter
def corridor_size(self, val: float):
self.client.set_global_var("corridor_size", val)
stitch_x = _GlobalVarParam(0, type_=int)
@property
def stitch_x(self):
val = self.client.get_global_var("stitch_x")
if val is None:
return 0
return val
@stitch_x.setter
@typechecked
def stitch_x(self, val: int):
self.client.set_global_var("stitch_x", val)
@property
def stitch_y(self):
val = self.client.get_global_var("stitch_y")
if val is None:
return 0
return val
@stitch_y.setter
@typechecked
def stitch_y(self, val: int):
self.client.set_global_var("stitch_y", val)
stitch_y = _GlobalVarParam(0, type_=int)
@property
def ptycho_reconstruct_foldername(self):
@@ -2056,38 +2044,11 @@ class Flomni(
self.client.set_global_var("ptycho_reconstruct_foldername", val)
self.reconstructor.folder_name = val # keep reconstructor in sync
@property
def tomo_angle_stepsize(self):
val = self.client.get_global_var("tomo_angle_stepsize")
if val is None:
return 10.0
return val
tomo_angle_stepsize = _GlobalVarParam(10.0)
@tomo_angle_stepsize.setter
def tomo_angle_stepsize(self, val: float):
self.client.set_global_var("tomo_angle_stepsize", val)
golden_max_number_of_projections = _GlobalVarParam(1000.0)
@property
def golden_max_number_of_projections(self):
val = self.client.get_global_var("golden_max_number_of_projections")
if val is None:
return 1000.0
return val
@golden_max_number_of_projections.setter
def golden_max_number_of_projections(self, val: float):
self.client.set_global_var("golden_max_number_of_projections", val)
@property
def tomo_stitch_overlap(self):
val = self.client.get_global_var("tomo_stitch_overlap")
if val is None:
return 0.2
return val
@tomo_stitch_overlap.setter
def tomo_stitch_overlap(self, val: float):
self.client.set_global_var("tomo_stitch_overlap", val)
tomo_stitch_overlap = _GlobalVarParam(0.2)
@property
def tomo_angle_range(self):
@@ -2105,16 +2066,7 @@ class Flomni(
raise ValueError("tomo_angle_range must be 180 or 360 degrees.")
self.client.set_global_var("tomo_angle_range", val)
@property
def golden_projections_at_0_deg_for_damage_estimation(self):
val = self.client.get_global_var("golden_projections_at_0_deg_for_damage_estimation")
if val is None:
return 0
return val
@golden_projections_at_0_deg_for_damage_estimation.setter
def golden_projections_at_0_deg_for_damage_estimation(self, val: float):
self.client.set_global_var("golden_projections_at_0_deg_for_damage_estimation", val)
golden_projections_at_0_deg_for_damage_estimation = _GlobalVarParam(0)
@property
def zero_deg_reference_at_each_subtomo(self):
@@ -2137,16 +2089,7 @@ class Flomni(
def zero_deg_reference_at_each_subtomo(self, val: bool):
self.client.set_global_var("zero_deg_reference_at_each_subtomo", val)
@property
def golden_ratio_bunch_size(self):
val = self.client.get_global_var("golden_ratio_bunch_size")
if val is None:
return 20
return val
@golden_ratio_bunch_size.setter
def golden_ratio_bunch_size(self, val: float):
self.client.set_global_var("golden_ratio_bunch_size", val)
golden_ratio_bunch_size = _GlobalVarParam(20)
@property
def frames_per_trigger(self):