style: british->american spelling
CI / lint (push) Skipped
CI / test (3.11) (push) Skipped
CI / test (3.12) (push) Skipped
CI / test (3.13) (push) Skipped
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
CI / test (3.11) (pull_request) Failing after 44s
CI / test (3.12) (pull_request) Failing after 41s
CI / test (3.13) (pull_request) Failing after 42s
CI / test-with-beamline-plugins (pxii_bec) (pull_request) Failing after 47s
CI / test-with-beamline-plugins (pxi_bec) (pull_request) Failing after 49s
CI / test-with-beamline-plugins (pxiii_bec) (pull_request) Failing after 1m0s
CI / test-with-coverage (pull_request) Failing after 1m1s
CI / coverage-analysis (pull_request) Skipped
CI / lint (pull_request) Failing after 2m2s
CI / lint (push) Skipped
CI / test (3.11) (push) Skipped
CI / test (3.12) (push) Skipped
CI / test (3.13) (push) Skipped
CI / test-with-beamline-plugins (pxi_bec) (push) Skipped
CI / test-with-beamline-plugins (pxii_bec) (push) Skipped
CI / test-with-beamline-plugins (pxiii_bec) (push) Skipped
CI / test (3.11) (pull_request) Failing after 44s
CI / test (3.12) (pull_request) Failing after 41s
CI / test (3.13) (pull_request) Failing after 42s
CI / test-with-beamline-plugins (pxii_bec) (pull_request) Failing after 47s
CI / test-with-beamline-plugins (pxi_bec) (pull_request) Failing after 49s
CI / test-with-beamline-plugins (pxiii_bec) (pull_request) Failing after 1m0s
CI / test-with-coverage (pull_request) Failing after 1m1s
CI / coverage-analysis (pull_request) Skipped
CI / lint (pull_request) Failing after 2m2s
This commit is contained in:
@@ -155,7 +155,7 @@ jobs:
|
||||
echo "percent=${percent}" >> "$GITHUB_OUTPUT"
|
||||
echo "Diff coverage: ${percent}%"
|
||||
|
||||
# Two artefacts on purpose: the full report is too big to post. The F5 WAF
|
||||
# Two artifacts on purpose: the full report is too big to post. The F5 WAF
|
||||
# in front of gitea.psi.ch rejects large POST bodies with an HTML 403, so
|
||||
# the comment body is capped and the detail lives in the artifact.
|
||||
- name: Build coverage summary
|
||||
|
||||
@@ -97,6 +97,9 @@ profile = "black"
|
||||
line_length = 100
|
||||
multi_line_output = 3
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
split-on-trailing-comma = false
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from importlib.resources import files
|
||||
|
||||
from aarecommon.config.beamline import MXBeamline
|
||||
from aarecommon.math.beam_center import BeamCenterFromDetectorStage
|
||||
from aarecommon.models.beam_centre import BeamCentre
|
||||
from aarecommon.models.beam_center import BeamCenter
|
||||
|
||||
from aare.beamline_dispatch.protocols import AuthDispatch, BeamlineDispatch, Geometry
|
||||
|
||||
@@ -21,13 +21,13 @@ class DefaultAuthDispatch(AuthDispatch):
|
||||
class DefaultGeometry(Geometry):
|
||||
def __init__(self, beamline: MXBeamline) -> None:
|
||||
super().__init__()
|
||||
with open(files("aarecommon.config") / "beamline_configs" / "beam_centres.json") as f:
|
||||
with open(files("aarecommon.config") / "beamline_configs" / "beam_centers.json") as f:
|
||||
measured = json.loads(f.read())[beamline.value.lower()]
|
||||
self._model = BeamCentre.model_validate(measured)
|
||||
self._model = BeamCenter.model_validate(measured)
|
||||
self._beamline = beamline
|
||||
|
||||
@property
|
||||
def beam_centre_model(self) -> BeamCenterFromDetectorStage:
|
||||
def beam_center_model(self) -> BeamCenterFromDetectorStage:
|
||||
return self._model.model
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class BecMacros(ABC):
|
||||
class Geometry(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def beam_centre_model(self) -> BeamCenterFromDetectorStage: ...
|
||||
def beam_center_model(self) -> BeamCenterFromDetectorStage: ...
|
||||
|
||||
|
||||
class BeamlineDispatch(ABC):
|
||||
|
||||
@@ -386,7 +386,7 @@ class AareWrapper:
|
||||
result=raster_result,
|
||||
sample_id=sample.db_id,
|
||||
attach_image=True,
|
||||
centre_of_mass=com,
|
||||
center_of_mass=com,
|
||||
raster_score=score, # TODO: Check whether AareDB needs to change for taking this input
|
||||
start_pxl=start_pxl,
|
||||
center_pxl=center_pxl,
|
||||
|
||||
@@ -456,4 +456,4 @@ def cancel_baton_request(cfg: BeamlineConfig, data: TokenData) -> dict:
|
||||
return {"error": True, "message": "You can only cancel your own request"}
|
||||
|
||||
cfg.clear_pending_baton_request()
|
||||
return {"cancelled": True, "message": "Request cancelled"}
|
||||
return {"canceled": True, "message": "Request canceled"}
|
||||
|
||||
@@ -612,7 +612,7 @@ class BeamlineConfig:
|
||||
|
||||
def zoom_for_pixel_to_mm(self, target_pixel_in_mm: float) -> float:
|
||||
"""Inverse of :meth:`pixel_to_mm`: the zoom at which one pixel covers
|
||||
``target_pixel_in_mm`` millimetres.
|
||||
``target_pixel_in_mm`` millimeters.
|
||||
|
||||
pixel_to_mm(z) = lens_factor / (b * exp(a*z)) =>
|
||||
z = ln(lens_factor / (b * target)) / a
|
||||
|
||||
+15
-15
@@ -693,7 +693,7 @@ class AareDAQ:
|
||||
current_step=None,
|
||||
steps=[
|
||||
StepState(step=WorkflowStateKind.MOUNT, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.LOOP_CENTRE, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.LOOP_CENTER, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.RASTER, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.DATA_COLLECTION, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.FINAL, status=StepStatus.PENDING),
|
||||
@@ -713,7 +713,7 @@ class AareDAQ:
|
||||
def _step_display_name(step: WorkflowStateKind) -> str:
|
||||
labels = {
|
||||
WorkflowStateKind.MOUNT: "Mount",
|
||||
WorkflowStateKind.LOOP_CENTRE: "Center",
|
||||
WorkflowStateKind.LOOP_CENTER: "Center",
|
||||
WorkflowStateKind.RASTER: "Raster",
|
||||
WorkflowStateKind.DATA_COLLECTION: "Collect",
|
||||
WorkflowStateKind.FINAL: "Paused/Finished",
|
||||
@@ -1294,10 +1294,10 @@ class AareDAQ:
|
||||
self._setup_datacollection(request=grid_request)
|
||||
logger.debug(f"Is detector simulated? {self._cfg.simulated_detector}")
|
||||
if not self._cfg.simulated_detector:
|
||||
logger.info("initialise detector for raster")
|
||||
logger.info("initialize detector for raster")
|
||||
status = self.status
|
||||
self._jfjoch.measure_raster(grid_request, status)
|
||||
logger.info("detector initialised")
|
||||
logger.info("detector initialized")
|
||||
else:
|
||||
logger.info("Simulated detector mode enabled; using fake raster result.")
|
||||
|
||||
@@ -1850,24 +1850,24 @@ class AareDAQ:
|
||||
except Exception:
|
||||
logger.exception("Failed to turn off blower")
|
||||
|
||||
def initialise_smargon(self):
|
||||
def initialize_smargon(self):
|
||||
self._cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self._devs.smargon_initialize()
|
||||
self._cfg.state_busy = False
|
||||
except Exception as e:
|
||||
self._cfg.state_busy = False
|
||||
logger.error(f"Failed to initialise Smargon: {e}")
|
||||
logger.error(f"Failed to initialize Smargon: {e}")
|
||||
raise
|
||||
|
||||
def initialise_detector(self):
|
||||
def initialize_detector(self):
|
||||
self._cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self._jfjoch.initialize()
|
||||
self._cfg.state_busy = False
|
||||
except Exception as e:
|
||||
self._cfg.state_busy = False
|
||||
logger.error(f"Failed to initialise detector: {e}")
|
||||
logger.error(f"Failed to initialize detector: {e}")
|
||||
raise
|
||||
|
||||
def recovery_unmount_sample(self) -> None:
|
||||
@@ -2627,7 +2627,7 @@ class AareDAQ:
|
||||
|
||||
logger.info(f"mounting done at {time.perf_counter() - start}")
|
||||
|
||||
self._mark_progress_running(progress, WorkflowStateKind.LOOP_CENTRE, "Centering sample")
|
||||
self._mark_progress_running(progress, WorkflowStateKind.LOOP_CENTER, "Centering sample")
|
||||
|
||||
local_contact_config = self.get_local_contact_config()
|
||||
mount_to_center_sleep_s = float(local_contact_config.mount_to_center_sleep_s)
|
||||
@@ -2652,7 +2652,7 @@ class AareDAQ:
|
||||
except LoopCenteringFailed as e:
|
||||
self._record_best_effort_step_failure(
|
||||
progress=progress,
|
||||
step=WorkflowStateKind.LOOP_CENTRE,
|
||||
step=WorkflowStateKind.LOOP_CENTER,
|
||||
error=e,
|
||||
sample=sample,
|
||||
code="LOOP_CENTERING_FAILED",
|
||||
@@ -2661,7 +2661,7 @@ class AareDAQ:
|
||||
if not centered:
|
||||
self._record_best_effort_step_failure(
|
||||
progress=progress,
|
||||
step=WorkflowStateKind.LOOP_CENTRE,
|
||||
step=WorkflowStateKind.LOOP_CENTER,
|
||||
error=LoopCenteringFailed("Centering returned no result"),
|
||||
sample=sample,
|
||||
code="LOOP_CENTERING_FAILED",
|
||||
@@ -2684,7 +2684,7 @@ class AareDAQ:
|
||||
logger.info(f"Face Detection done at {time.perf_counter() - start}")
|
||||
|
||||
self._mark_progress_success(
|
||||
progress, WorkflowStateKind.LOOP_CENTRE, "Centering complete"
|
||||
progress, WorkflowStateKind.LOOP_CENTER, "Centering complete"
|
||||
)
|
||||
|
||||
self._mark_progress_running(progress, WorkflowStateKind.RASTER, "Running raster")
|
||||
@@ -3158,7 +3158,7 @@ class AareDAQ:
|
||||
dtz_mm=dtz,
|
||||
detector_size_pxl=(width, height),
|
||||
pixel_size_mm=pixel_size_mm,
|
||||
beam_center_pxl=self._devs.detector_beam_centre_px,
|
||||
beam_center_pxl=self._devs.detector_beam_center_px,
|
||||
detector_description=detector_description,
|
||||
detector_serial_number=detector_serial_number,
|
||||
poni_rot1_rad=-0.001396263,
|
||||
@@ -3438,11 +3438,11 @@ class AareDAQ:
|
||||
return []
|
||||
return [str(item) for item in devices]
|
||||
|
||||
def bec_reinitialise_planner_and_position_devices(self, method: str = "auto") -> list[str]:
|
||||
def bec_reinitialize_planner_and_position_devices(self, method: str = "auto") -> list[str]:
|
||||
self._cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self._devs.bec_worker.load_user_macros()
|
||||
return self._devs.bec_worker.reinitialise_planner_and_position_devices(method=method)
|
||||
return self._devs.bec_worker.reinitialize_planner_and_position_devices(method=method)
|
||||
finally:
|
||||
self._cfg.state_busy = False
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ class BeamlineDevices:
|
||||
BEAMLINE = beamline.value.upper()
|
||||
self.tell = make_tell_client(beamline)
|
||||
self.aerotech = aerotech.AerotechController(beamline)
|
||||
logger.debug("initialising BEC worker")
|
||||
logger.debug("initializing BEC worker")
|
||||
self.bec_worker = BECClientWorker(beamline)
|
||||
logger.debug("initialising BEC worker done")
|
||||
logger.debug("initializing BEC worker done")
|
||||
self._smargon = smargon.Smargon(beamline)
|
||||
self.exp_shutter = ExperimentalHutchShutter(beamline=self._beamline)
|
||||
# Personnel Safety System: gates whether the robot is allowed to move.
|
||||
@@ -160,8 +160,8 @@ class BeamlineDevices:
|
||||
return self._front_light.value
|
||||
|
||||
@property
|
||||
def detector_beam_centre_px(self) -> tuple[float, float]:
|
||||
beam_center_x, beam_center_y = self._dispatch.geo.beam_centre_model.predict(
|
||||
def detector_beam_center_px(self) -> tuple[float, float]:
|
||||
beam_center_x, beam_center_y = self._dispatch.geo.beam_center_model.predict(
|
||||
self.dtz, self.dty
|
||||
)
|
||||
return float(beam_center_x[0]), float(beam_center_y[0])
|
||||
|
||||
@@ -45,5 +45,5 @@ def build_fake_raster_result(request: RasterGridRequest) -> CompletedRasterGridE
|
||||
file_prefix=request.file_prefix, image_count=request.n_x * request.n_y, rotation=False
|
||||
)
|
||||
return CompletedRasterGridElem(
|
||||
request=copy.deepcopy(request), result=result, centre_of_mass=None
|
||||
request=copy.deepcopy(request), result=result, center_of_mass=None
|
||||
)
|
||||
|
||||
@@ -48,7 +48,7 @@ class FaceDetectionService:
|
||||
self._progress_emitter().emit_progress(payload)
|
||||
return payload
|
||||
|
||||
def _centre_correction(self, model: MLBoxModel, tolerance: float = 0.2) -> None:
|
||||
def _center_correction(self, model: MLBoxModel, tolerance: float = 0.2) -> None:
|
||||
geom = self.ctx.runtime.sample_geometry
|
||||
beam_y = geom.beam_location_pxl.y
|
||||
beam_x = geom.beam_location_pxl.x
|
||||
@@ -56,10 +56,10 @@ class FaceDetectionService:
|
||||
y1 = model.box.top_y
|
||||
y2 = model.box.bottom_y
|
||||
|
||||
centre_y = y1 + (y2 - y1) / 2
|
||||
center_y = y1 + (y2 - y1) / 2
|
||||
|
||||
if beam_y != 0 and abs(centre_y - beam_y) / abs(beam_y) > tolerance:
|
||||
coord = geom.picture_to_smargon(Coordinate(x=beam_x, y=centre_y))
|
||||
if beam_y != 0 and abs(center_y - beam_y) / abs(beam_y) > tolerance:
|
||||
coord = geom.picture_to_smargon(Coordinate(x=beam_x, y=center_y))
|
||||
self.ctx.deps.devs.smargon_pos = SmargonCoordinate(sh_mm=coord)
|
||||
self.ctx.deps.devs.smargon_wait(60)
|
||||
|
||||
@@ -126,7 +126,7 @@ class FaceDetectionService:
|
||||
model.box.bottom_y,
|
||||
)
|
||||
|
||||
self._centre_correction(model, tolerance=0.2)
|
||||
self._center_correction(model, tolerance=0.2)
|
||||
|
||||
if cls_id == 3:
|
||||
boxes_face[angle] = (x1, y1, x2, y2)
|
||||
|
||||
@@ -81,7 +81,7 @@ class LoopCenteringAnalyzer:
|
||||
sh_mm=geom.picture_to_smargon(Coordinate(x=target_point[0], y=target_point[1]))
|
||||
)
|
||||
|
||||
def _interpret_ml_loop_centre_box(
|
||||
def _interpret_ml_loop_center_box(
|
||||
self, boxes
|
||||
) -> tuple[SmargonCoordinate | None, int | None, list[int]]:
|
||||
if boxes is None:
|
||||
@@ -89,7 +89,7 @@ class LoopCenteringAnalyzer:
|
||||
|
||||
classes: list[int] = []
|
||||
pin = None
|
||||
centre_x, centre_y = None, None
|
||||
center_x, center_y = None, None
|
||||
|
||||
for box in boxes.boxes.values():
|
||||
if box and box.cls is not None:
|
||||
@@ -113,33 +113,33 @@ class LoopCenteringAnalyzer:
|
||||
|
||||
if cls == MLBoxType.LOOP_ALL.value:
|
||||
if y1 + y2 <= x1 + x2:
|
||||
centre_y = y1 + (y2 - y1) / 2
|
||||
centre_x = x1
|
||||
center_y = y1 + (y2 - y1) / 2
|
||||
center_x = x1
|
||||
elif pin:
|
||||
position_dict = self.ctx.deps.mlbox.check_box_relation(pin, best_box)
|
||||
if position_dict["overlap_y"] and position_dict["overlap_x"]:
|
||||
centre_y = y1 + (y2 - y1) / 2
|
||||
centre_x = x1
|
||||
center_y = y1 + (y2 - y1) / 2
|
||||
center_x = x1
|
||||
cls = MLBoxType.PIN.value
|
||||
else:
|
||||
centre_y = y2 if position_dict["top"] else y1
|
||||
centre_x = x1 + (x2 - x1) / 2
|
||||
center_y = y2 if position_dict["top"] else y1
|
||||
center_x = x1 + (x2 - x1) / 2
|
||||
else:
|
||||
centre_y = y1
|
||||
centre_x = x1 + (x2 - x1) / 2
|
||||
center_y = y1
|
||||
center_x = x1 + (x2 - x1) / 2
|
||||
|
||||
elif cls == MLBoxType.PIN.value:
|
||||
centre_y = y1 + (y2 - y1) / 2
|
||||
centre_x = x1
|
||||
center_y = y1 + (y2 - y1) / 2
|
||||
center_x = x1
|
||||
|
||||
elif cls in (MLBoxType.CRYSTAL.value, MLBoxType.LOOP_FACE.value):
|
||||
centre_y = y1 + (y2 - y1) / 2
|
||||
centre_x = x1 + (x2 - x1) / 2
|
||||
center_y = y1 + (y2 - y1) / 2
|
||||
center_x = x1 + (x2 - x1) / 2
|
||||
|
||||
else:
|
||||
return None, cls, classes
|
||||
|
||||
coord = geom.picture_to_smargon(Coordinate(x=centre_x, y=centre_y))
|
||||
coord = geom.picture_to_smargon(Coordinate(x=center_x, y=center_y))
|
||||
return SmargonCoordinate(sh_mm=coord), cls, classes
|
||||
|
||||
def analyze_angle(
|
||||
@@ -159,7 +159,7 @@ class LoopCenteringAnalyzer:
|
||||
predicted_target = self._extract_prediction_target(
|
||||
target_point=prediction_result.target_point
|
||||
)
|
||||
calculated_target, selected_class, classes = self._interpret_ml_loop_centre_box(
|
||||
calculated_target, selected_class, classes = self._interpret_ml_loop_center_box(
|
||||
prediction_result.predictions
|
||||
)
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ class LoopCenteringService:
|
||||
|
||||
else:
|
||||
alc_comment = (
|
||||
"Failed to centre but detected objects - "
|
||||
"Failed to center but detected objects - "
|
||||
f"Crystal: {found_classes_count.get(2, 0)}, "
|
||||
f"Loop_face: {found_classes_count.get(3, 0)}, "
|
||||
f"Loop_all: {found_classes_count.get(0, 0)}, "
|
||||
|
||||
@@ -52,7 +52,7 @@ class RasterService:
|
||||
return len(scan_result.images)
|
||||
|
||||
@staticmethod
|
||||
def _grid_image_id_from_centre_offset(
|
||||
def _grid_image_id_from_center_offset(
|
||||
*, x_mm: float, y_mm: float, request: RasterGridRequest
|
||||
) -> int:
|
||||
if request.grid_size_mm.x <= 0 or request.grid_size_mm.y <= 0:
|
||||
@@ -235,7 +235,7 @@ class RasterService:
|
||||
beam_x_pxl = geom.beam_location_pxl.x
|
||||
beam_y_pxl = geom.beam_location_pxl.y
|
||||
|
||||
line_scan_centre = geom.picture_to_smargon(Coordinate(x=beam_x_pxl, y=beam_y_pxl))
|
||||
line_scan_center = geom.picture_to_smargon(Coordinate(x=beam_x_pxl, y=beam_y_pxl))
|
||||
n_y = default_n_y
|
||||
|
||||
prediction_result: MLBoxPredictionResult = self.ctx.deps.mlbox.predict(
|
||||
@@ -275,7 +275,7 @@ class RasterService:
|
||||
y_retarget_threshold_mm = geom.beam_size_mm.y * 2.0
|
||||
|
||||
if y_delta_mm > y_retarget_threshold_mm:
|
||||
line_scan_centre = geom.picture_to_smargon(Coordinate(x=beam_x_pxl, y=target_y_pxl))
|
||||
line_scan_center = geom.picture_to_smargon(Coordinate(x=beam_x_pxl, y=target_y_pxl))
|
||||
self.logger.info(
|
||||
"Using ML target y for second auto-center raster",
|
||||
extra=merge_log_context(
|
||||
@@ -287,15 +287,15 @@ class RasterService:
|
||||
"target_y_pxl": target_y_pxl,
|
||||
"y_delta_mm": y_delta_mm,
|
||||
"threshold_mm": y_retarget_threshold_mm,
|
||||
"target_sh_x_mm": line_scan_centre.x,
|
||||
"target_sh_y_mm": line_scan_centre.y,
|
||||
"target_sh_z_mm": line_scan_centre.z,
|
||||
"target_sh_x_mm": line_scan_center.x,
|
||||
"target_sh_y_mm": line_scan_center.y,
|
||||
"target_sh_z_mm": line_scan_center.z,
|
||||
},
|
||||
),
|
||||
)
|
||||
else:
|
||||
self.logger.info(
|
||||
"Keeping beam-centred y line scan because ML target y shift is small",
|
||||
"Keeping beam-centered y line scan because ML target y shift is small",
|
||||
extra=merge_log_context(
|
||||
sample_log_context(self.ctx.sample),
|
||||
{
|
||||
@@ -310,7 +310,7 @@ class RasterService:
|
||||
)
|
||||
else:
|
||||
self.logger.info(
|
||||
"No ML target point for second auto-center raster; using beam-centred line scan",
|
||||
"No ML target point for second auto-center raster; using beam-centered line scan",
|
||||
extra=merge_log_context(
|
||||
sample_log_context(self.ctx.sample),
|
||||
{
|
||||
@@ -362,7 +362,7 @@ class RasterService:
|
||||
|
||||
offset = Coordinate(x=-grid_size_mm.x / 2.0, y=-(n_y - 1) * grid_size_mm.y / 2.0)
|
||||
top_left = SmargonCoordinate(
|
||||
sh_mm=line_scan_centre + geom.smargon_nudge(offset),
|
||||
sh_mm=line_scan_center + geom.smargon_nudge(offset),
|
||||
phi_deg=geom.smargon.phi_deg,
|
||||
chi_deg=geom.smargon.chi_deg,
|
||||
)
|
||||
@@ -486,7 +486,7 @@ class RasterService:
|
||||
|
||||
com = raster_highest_score(scan_result.images)
|
||||
if com is None:
|
||||
self.logger.info("Calcualted COM is None using centre image")
|
||||
self.logger.info("Calcualted COM is None using center image")
|
||||
if request.n_x == 1:
|
||||
x = request.grid_size_mm.x / 2.0
|
||||
else:
|
||||
@@ -498,14 +498,14 @@ class RasterService:
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
"Calculated raster centre offset",
|
||||
"Calculated raster center offset",
|
||||
extra=merge_log_context(
|
||||
sample_log_context(self.ctx.sample),
|
||||
raster_request_log_context(request),
|
||||
{
|
||||
"centre_offset_x_mm": target_coor_offset.x,
|
||||
"centre_offset_y_mm": target_coor_offset.y,
|
||||
"centre_offset_z_mm": target_coor_offset.z,
|
||||
"center_offset_x_mm": target_coor_offset.x,
|
||||
"center_offset_y_mm": target_coor_offset.y,
|
||||
"center_offset_z_mm": target_coor_offset.z,
|
||||
"grid_half_width_x_mm": x,
|
||||
"grid_half_height_y_mm": y,
|
||||
"top_left_x_mm": getattr(request.smargon_top_left.sh_mm, "x", None),
|
||||
@@ -519,14 +519,14 @@ class RasterService:
|
||||
target_coor = com.get_com_mm(request)
|
||||
target_coor_offset = self.ctx.sample_geometry.smargon_nudge(target_coor)
|
||||
self.logger.info(
|
||||
"Calculated raster centre offset",
|
||||
"Calculated raster center offset",
|
||||
extra=merge_log_context(
|
||||
sample_log_context(self.ctx.sample),
|
||||
raster_request_log_context(request),
|
||||
{
|
||||
"centre_offset_x_mm": target_coor_offset.x,
|
||||
"centre_offset_y_mm": target_coor_offset.y,
|
||||
"centre_offset_z_mm": target_coor_offset.z,
|
||||
"center_offset_x_mm": target_coor_offset.x,
|
||||
"center_offset_y_mm": target_coor_offset.y,
|
||||
"center_offset_z_mm": target_coor_offset.z,
|
||||
"grid_half_width_x_mm": x,
|
||||
"grid_half_height_y_mm": y,
|
||||
"top_left_x_mm": getattr(request.smargon_top_left.sh_mm, "x", None),
|
||||
@@ -536,7 +536,7 @@ class RasterService:
|
||||
),
|
||||
)
|
||||
|
||||
self.logger.info(f"moving Smargon to grid centre offset {target_coor_offset}")
|
||||
self.logger.info(f"moving Smargon to grid center offset {target_coor_offset}")
|
||||
target_smargon = SmargonCoordinate(
|
||||
sh_mm=request.smargon_top_left.sh_mm + target_coor_offset,
|
||||
phi_deg=request.smargon_top_left.phi_deg,
|
||||
@@ -547,16 +547,16 @@ class RasterService:
|
||||
self.ctx.deps.devs.smargon_wait(timeout=180)
|
||||
|
||||
self.logger.info(
|
||||
"Moved Smargon to raster centre",
|
||||
"Moved Smargon to raster center",
|
||||
extra=merge_log_context(
|
||||
sample_log_context(self.ctx.sample),
|
||||
raster_request_log_context(request),
|
||||
{
|
||||
"centre_sh_x_mm": target_smargon.sh_mm.x,
|
||||
"centre_sh_y_mm": target_smargon.sh_mm.y,
|
||||
"centre_sh_z_mm": target_smargon.sh_mm.z,
|
||||
"centre_phi_deg": target_smargon.phi_deg,
|
||||
"centre_chi_deg": target_smargon.chi_deg,
|
||||
"center_sh_x_mm": target_smargon.sh_mm.x,
|
||||
"center_sh_y_mm": target_smargon.sh_mm.y,
|
||||
"center_sh_z_mm": target_smargon.sh_mm.z,
|
||||
"center_phi_deg": target_smargon.phi_deg,
|
||||
"center_chi_deg": target_smargon.chi_deg,
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -605,7 +605,7 @@ class RasterService:
|
||||
diffraction_image_filename = (
|
||||
f"{self.ctx.sample.db_id}_diffraction_image_near_grid_scan"
|
||||
)
|
||||
diffraction_image_id = self._grid_image_id_from_centre_offset(
|
||||
diffraction_image_id = self._grid_image_id_from_center_offset(
|
||||
x_mm=x, y_mm=y, request=request
|
||||
)
|
||||
|
||||
@@ -646,7 +646,7 @@ class RasterService:
|
||||
self.ctx.deps.cfg.last_best_res = get_best_res(result_list=scan_result.images)
|
||||
self.ctx.deps.cfg.last_best_b_factor = get_best_b_factor(result_list=scan_result.images)
|
||||
return CompletedRasterGridElem(
|
||||
request=copy.deepcopy(request), result=scan_result, centre_of_mass=com
|
||||
request=copy.deepcopy(request), result=scan_result, center_of_mass=com
|
||||
)
|
||||
|
||||
except Exception:
|
||||
@@ -763,9 +763,9 @@ class RasterService:
|
||||
|
||||
status = self.ctx.status
|
||||
if not self.ctx.deps.cfg.simulated_detector:
|
||||
self.logger.info("initialise detector")
|
||||
self.logger.info("initialize detector")
|
||||
self.ctx.deps.jfjoch.measure_raster(grid, status)
|
||||
self.logger.info("detector initialised")
|
||||
self.logger.info("detector initialized")
|
||||
else:
|
||||
self.logger.info("Simulated detector mode enabled; using fake raster result.")
|
||||
|
||||
@@ -829,9 +829,9 @@ class RasterService:
|
||||
|
||||
status = self.ctx.status
|
||||
if not self.ctx.deps.cfg.simulated_detector:
|
||||
self.logger.info(f"initialise detector for raster at {grid.omega_deg}")
|
||||
self.logger.info(f"initialize detector for raster at {grid.omega_deg}")
|
||||
self.ctx.deps.jfjoch.measure_raster(grid, status)
|
||||
self.logger.info("detector initialised")
|
||||
self.logger.info("detector initialized")
|
||||
else:
|
||||
self.logger.info("Simulated detector mode enabled; using fake raster result.")
|
||||
|
||||
|
||||
+18
-18
@@ -95,7 +95,7 @@ class AareUvicornWorker(UvicornWorker):
|
||||
async def lifespan(application: FastAPI):
|
||||
"""
|
||||
Runs once per worker process, AFTER fork() and BEFORE serving requests.
|
||||
All stateful / connection-opening initialisation belongs here so that
|
||||
All stateful / connection-opening initialization belongs here so that
|
||||
each worker gets its own fresh Redis, BEC, EPICS, and TELL connections.
|
||||
"""
|
||||
global cfg, daq, bl_dispatch
|
||||
@@ -103,7 +103,7 @@ async def lifespan(application: FastAPI):
|
||||
logger.info(f"Worker {os.getpid()} setting up JWT authentication...")
|
||||
bl_dispatch = get_beamline_dispatch()
|
||||
auth.init_jwt_key(bl_dispatch.auth)
|
||||
logger.info(f"Worker {os.getpid()} starting initialisation...")
|
||||
logger.info(f"Worker {os.getpid()} starting initialization...")
|
||||
|
||||
# ── Core objects (Redis, EPICS PVs, BEC, TELL, JFJoch, etc.) ──
|
||||
bl = mx_beamline()
|
||||
@@ -128,7 +128,7 @@ async def lifespan(application: FastAPI):
|
||||
daq.set_face_detection_progress_callback(_push_face_detection_progress)
|
||||
daq.set_automation_progress_callback(_push_automation_progress)
|
||||
|
||||
logger.info(f"Worker {os.getpid()} initialised successfully.")
|
||||
logger.info(f"Worker {os.getpid()} initialized successfully.")
|
||||
|
||||
yield # ── application serves requests here ──
|
||||
|
||||
@@ -486,7 +486,7 @@ async def mono_pitch_scan(plot: bool = False, token: str = Depends(oauth2_scheme
|
||||
@app.get("/beamline/steer_beam_available")
|
||||
async def steer_beam_available(token: str = Depends(oauth2_scheme)):
|
||||
"""
|
||||
Check if the beam centring routine is available.
|
||||
Check if the beam centering routine is available.
|
||||
|
||||
Args:
|
||||
token: OAuth2 access token.
|
||||
@@ -624,9 +624,9 @@ async def anneal(time_s: float, token: str = Depends(oauth2_scheme)):
|
||||
|
||||
|
||||
@app.post("/smargon/initialize")
|
||||
async def initialise_smargon(token: str = Depends(oauth2_scheme)) -> dict:
|
||||
async def initialize_smargon(token: str = Depends(oauth2_scheme)) -> dict:
|
||||
"""
|
||||
Initialise Smargon. Staff only.
|
||||
Initialize Smargon. Staff only.
|
||||
|
||||
Args:
|
||||
token: OAuth2 access token.
|
||||
@@ -636,8 +636,8 @@ async def initialise_smargon(token: str = Depends(oauth2_scheme)) -> dict:
|
||||
"""
|
||||
data = auth.parse_token(token)
|
||||
auth.check_jwt_staff_only(data)
|
||||
daq.initialise_smargon()
|
||||
return {"ok": True, "message": "Smargon initialised."}
|
||||
daq.initialize_smargon()
|
||||
return {"ok": True, "message": "Smargon initialized."}
|
||||
|
||||
|
||||
@app.post("/bec/load_user_macros")
|
||||
@@ -671,12 +671,12 @@ async def bec_list_all_devices(token: str = Depends(oauth2_scheme)) -> list:
|
||||
return daq.bec_list_all_devices()
|
||||
|
||||
|
||||
@app.post("/bec/reinitialise_planner_and_position_devices")
|
||||
async def bec_reinitialise_planner_and_position_devices(
|
||||
@app.post("/bec/reinitialize_planner_and_position_devices")
|
||||
async def bec_reinitialize_planner_and_position_devices(
|
||||
method: str = "auto", token: str = Depends(oauth2_scheme)
|
||||
) -> dict:
|
||||
"""
|
||||
Reinitialise BEC planner and position devices. Staff only.
|
||||
Reinitialize BEC planner and position devices. Staff only.
|
||||
|
||||
Args:
|
||||
method:
|
||||
@@ -687,12 +687,12 @@ async def bec_reinitialise_planner_and_position_devices(
|
||||
"""
|
||||
data = auth.parse_token(token)
|
||||
auth.check_jwt_staff_only(data)
|
||||
position_devices = daq.bec_reinitialise_planner_and_position_devices(method=method)
|
||||
position_devices = daq.bec_reinitialize_planner_and_position_devices(method=method)
|
||||
return {
|
||||
"ok": True,
|
||||
"method": method,
|
||||
"position_devices": position_devices,
|
||||
"message": "BEC planner and position devices reinitialised.",
|
||||
"message": "BEC planner and position devices reinitialized.",
|
||||
}
|
||||
|
||||
|
||||
@@ -729,14 +729,14 @@ async def bec_save_current_aerotech_position(token: str = Depends(oauth2_scheme)
|
||||
return {"ok": True, "message": "Saved current BEC aerotech work position and reloaded devices."}
|
||||
|
||||
|
||||
def initialise_aerotech(self):
|
||||
def initialize_aerotech(self):
|
||||
self._cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self._devs.aerotech.home_aerotech()
|
||||
self._cfg.state_busy = False
|
||||
except Exception as e:
|
||||
self._cfg.state_busy = False
|
||||
logger.error(f"Failed to initialise Aerotech: {e}")
|
||||
logger.error(f"Failed to initialize Aerotech: {e}")
|
||||
raise
|
||||
|
||||
|
||||
@@ -751,14 +751,14 @@ def detector_take_pedestal(self):
|
||||
raise
|
||||
|
||||
|
||||
def initialise_detector(self):
|
||||
def initialize_detector(self):
|
||||
self._cfg.try_set_busy(timeout=360)
|
||||
try:
|
||||
self._jfjoch.initialize()
|
||||
self._cfg.state_busy = False
|
||||
except Exception as e:
|
||||
self._cfg.state_busy = False
|
||||
logger.error(f"Failed to initialise detector: {e}")
|
||||
logger.error(f"Failed to initialize detector: {e}")
|
||||
raise
|
||||
|
||||
|
||||
@@ -2457,7 +2457,7 @@ async def fluorimeter_stream() -> AsyncGenerator[str, None]:
|
||||
break
|
||||
await asyncio.sleep(0.2)
|
||||
except asyncio.CancelledError as e:
|
||||
logger.error(f">>> Fluorimeter stream cancelled: {e}")
|
||||
logger.error(f">>> Fluorimeter stream canceled: {e}")
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ def xtal_snapshot2xrf(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
|
||||
|
||||
def xtal_snapshot2bl(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALISATION)
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALIZATION)
|
||||
|
||||
|
||||
def xtal_snapshot2dh(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
@@ -207,7 +207,7 @@ def flux_measurement2ba(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
|
||||
|
||||
def flux_measurement2bl(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALISATION)
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALIZATION)
|
||||
|
||||
|
||||
def ba2flux_measurement(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
@@ -230,7 +230,7 @@ def ba2sa(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
|
||||
|
||||
def sa2bl(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALISATION)
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALIZATION)
|
||||
devs.samcam_settings.exposure = 0.001
|
||||
# TODO SAMCAM SETTINGS SHOULD BE DOEN via zoom settings
|
||||
|
||||
@@ -246,7 +246,7 @@ def bl2ba(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
|
||||
|
||||
def ba2bl(devs: BeamlineDevices, cfg: BeamlineConfig):
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALISATION)
|
||||
devs.bec_worker.move_to(BeamlineState.BEAM_VISUALIZATION)
|
||||
devs.samcam_settings.exposure = 0.001
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class BeamlineState(str, Enum):
|
||||
DATA_COLLECTION = "data_collection"
|
||||
DC_XRF = "DC_XRF"
|
||||
MANUAL_SAMPLE_EXCHANGE = "manual_sample_exchange"
|
||||
BEAM_VISUALISATION = "beam_visualisation"
|
||||
BEAM_VISUALIZATION = "beam_visualization"
|
||||
FLUX_MEASUREMENT = "flux_measurement"
|
||||
BEAMSTOP_ALIGNMENT = "beamstop_alignment"
|
||||
MAINTENANCE = "maintenance"
|
||||
@@ -57,7 +57,7 @@ def _bec_state_to_aare_state(bec_state: BeamlineState) -> BeamlineStateEnum:
|
||||
BeamlineState.DATA_COLLECTION: BeamlineStateEnum.DataCollection,
|
||||
BeamlineState.DC_XRF: BeamlineStateEnum.XrayFluorescence,
|
||||
BeamlineState.MANUAL_SAMPLE_EXCHANGE: BeamlineStateEnum.SampleExchange,
|
||||
BeamlineState.BEAM_VISUALISATION: BeamlineStateEnum.BeamLocation,
|
||||
BeamlineState.BEAM_VISUALIZATION: BeamlineStateEnum.BeamLocation,
|
||||
BeamlineState.FLUX_MEASUREMENT: BeamlineStateEnum.FluxMeasurement,
|
||||
BeamlineState.BEAMSTOP_ALIGNMENT: BeamlineStateEnum.BeamstopAlignment,
|
||||
BeamlineState.MAINTENANCE: BeamlineStateEnum.Maintenance,
|
||||
@@ -108,7 +108,7 @@ class BECClientWorker:
|
||||
try:
|
||||
self._init_beamline_environment()
|
||||
except Exception:
|
||||
logger.exception("Error initialising BEC devices")
|
||||
logger.exception("Error initializing BEC devices")
|
||||
sys.exit(1)
|
||||
logger.debug(f"simulated is {self.simulated}")
|
||||
|
||||
@@ -120,7 +120,7 @@ class BECClientWorker:
|
||||
self._zoom = self.dev.scam_zoom
|
||||
self._ring_current = self.dev.sls_current
|
||||
except Exception as e:
|
||||
logger.error(f"Error initialising planner and position devices: {e}")
|
||||
logger.error(f"Error initializing planner and position devices: {e}")
|
||||
self.position_devices = None
|
||||
self.planner = None
|
||||
self._backlight_brightness = None
|
||||
@@ -129,10 +129,10 @@ class BECClientWorker:
|
||||
self._zoom = self.dev.scam_zoom
|
||||
self._ring_current = self.dev.sls_current
|
||||
except Exception as e:
|
||||
logger.exception("Error initialising zoom and ring_current")
|
||||
logger.exception("Error initializing zoom and ring_current")
|
||||
self._zoom = None
|
||||
self.ring_current = None
|
||||
raise RuntimeError(f"Error initialising BEC devices: {e}") from e
|
||||
raise RuntimeError(f"Error initializing BEC devices: {e}") from e
|
||||
|
||||
def read_current_state(self) -> BeamlineStateEnum:
|
||||
if self.planner is None:
|
||||
@@ -341,9 +341,9 @@ class BECClientWorker:
|
||||
logger.warning("BEC load_all_user_macros returned None")
|
||||
return result
|
||||
|
||||
def reinitialise_planner_and_position_devices(self, method: str = "auto"):
|
||||
def reinitialize_planner_and_position_devices(self, method: str = "auto"):
|
||||
"""
|
||||
Reinitialise BEC position devices and planner.
|
||||
Reinitialize BEC position devices and planner.
|
||||
|
||||
Args:
|
||||
method:
|
||||
@@ -352,21 +352,21 @@ class BECClientWorker:
|
||||
"sample" - force init_se_devices() + planner creation.
|
||||
|
||||
Returns:
|
||||
List of position device names after reinitialisation.
|
||||
List of position device names after reinitialization.
|
||||
"""
|
||||
if self.simulated:
|
||||
logger.debug(f"Simulating reinitialise_planner_and_position_devices(method={method})")
|
||||
logger.debug(f"Simulating reinitialize_planner_and_position_devices(method={method})")
|
||||
return []
|
||||
try:
|
||||
self.client.config.update_session_with_file(
|
||||
f"/sls/{self.beamline}/config/bec/production/{self._beamline_name}_bec/{self._beamline_name}_bec/device_configs/{self._beamline_name}-devices.yaml"
|
||||
)
|
||||
self._init_beamline_environment()
|
||||
logger.info(f"Reinitialised BEC planner and position devices using method={method}")
|
||||
logger.info(f"Reinitialized BEC planner and position devices using method={method}")
|
||||
return self.list_position_devices()
|
||||
except Exception as e:
|
||||
raise self._bec_error(
|
||||
e, operation=f"reinitialise_planner_and_position_devices:{method}"
|
||||
e, operation=f"reinitialize_planner_and_position_devices:{method}"
|
||||
) from e
|
||||
|
||||
def shutdown_client(self):
|
||||
|
||||
@@ -144,7 +144,7 @@ class JFJochWrapper:
|
||||
pgroup = s.sample.user
|
||||
sample = s.sample.sample_name
|
||||
|
||||
# raster grid, rotation or screening specific parameter initialisation
|
||||
# raster grid, rotation or screening specific parameter initialization
|
||||
wedge = None
|
||||
if isinstance(r, RasterGridRequest):
|
||||
data_folder = f"{pgroup}/raw/raster"
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ def main():
|
||||
if not token or token.count(".") != 2:
|
||||
raise RuntimeError(
|
||||
"Authentication did not return a valid token. "
|
||||
"Please check the server is running (it may still be initialising)."
|
||||
"Please check the server is running (it may still be initializing)."
|
||||
)
|
||||
logger.info("Authentication successful")
|
||||
splash.set_progress(80, "Authentication successful...")
|
||||
|
||||
+12
-12
@@ -275,7 +275,7 @@ class MainWindow(QMainWindow):
|
||||
None,
|
||||
"Authentication Error",
|
||||
"Could not start the GUI because authentication data was invalid.\n\n"
|
||||
"Most commonly the server is not running yet (or is still initialising).\n"
|
||||
"Most commonly the server is not running yet (or is still initializing).\n"
|
||||
"Please start/restart the server and try again.",
|
||||
)
|
||||
raise
|
||||
@@ -365,7 +365,7 @@ class MainWindow(QMainWindow):
|
||||
# documentMode: no pane frame, so the fixed-width panels aren't inset.
|
||||
self.left_column_tabs = QTabWidget(self.left_column)
|
||||
self.left_column_tabs.setDocumentMode(True)
|
||||
# documentMode draws a grey base line across the bar's full width.
|
||||
# documentMode draws a gray base line across the bar's full width.
|
||||
self.left_column_tabs.tabBar().setDrawBase(False)
|
||||
|
||||
beamline_page = QWidget()
|
||||
@@ -618,7 +618,7 @@ class MainWindow(QMainWindow):
|
||||
self.job_list_panel.hide()
|
||||
|
||||
# Queue controls act on the queue, whose order only the Queued chip
|
||||
# view shows — so they are live there and greyed out elsewhere. The
|
||||
# view shows — so they are live there and grayed out elsewhere. The
|
||||
# pop-out clones register themselves in _clone_automation_row. "run"
|
||||
# kind stays enabled while automation runs: pausing is always allowed.
|
||||
self._queue_action_buttons: list[tuple[QPushButton, str]] = [
|
||||
@@ -638,7 +638,7 @@ class MainWindow(QMainWindow):
|
||||
self.sample_lists_tabs.addTab(dewar_tab, "Dewar samples")
|
||||
self.sample_lists_tabs.addTab(self.ref_tools_panel, "Auxiliary puck")
|
||||
# Non-staff never get reference-tools data (the DAQ connect below is
|
||||
# staff-gated). Grey the tab out instead of hiding it: every role sees
|
||||
# staff-gated). Gray the tab out instead of hiding it: every role sees
|
||||
# the same view, and clicking the locked tab says why it is locked.
|
||||
if not self._decoded_token.staff:
|
||||
self.sample_lists_tabs.setTabEnabled(1, False)
|
||||
@@ -2509,7 +2509,7 @@ class MainWindow(QMainWindow):
|
||||
current_step=None,
|
||||
steps=[
|
||||
StepState(step=WorkflowStateKind.MOUNT, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.LOOP_CENTRE, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.LOOP_CENTER, status=StepStatus.PENDING),
|
||||
StepState(step=WorkflowStateKind.RASTER, status=StepStatus.PENDING),
|
||||
StepState(
|
||||
step=WorkflowStateKind.DATA_COLLECTION, status=StepStatus.PENDING
|
||||
@@ -2620,7 +2620,7 @@ class MainWindow(QMainWindow):
|
||||
|
||||
def _apply_session_gate(self, session_state) -> None:
|
||||
# No baton -> watching only: camera views stay live, every operating
|
||||
# surface is greyed. The SESSION VACANT badge (and the status bar
|
||||
# surface is grayed. The SESSION VACANT badge (and the status bar
|
||||
# session menu) remain the way back in.
|
||||
owned = session_state in (SessionsStateEnum.OwnedByYou, SessionsStateEnum.PendingElseToYou)
|
||||
if owned == getattr(self, "_session_operations_enabled", None):
|
||||
@@ -2655,7 +2655,7 @@ class MainWindow(QMainWindow):
|
||||
banner.set_collapsed(True, persist=False)
|
||||
|
||||
# Watch-only shows ONLY the camera stream: every other operating
|
||||
# surface is hidden outright (not just greyed), and regaining the
|
||||
# surface is hidden outright (not just grayed), and regaining the
|
||||
# baton restores exactly the visibility each one had before. The
|
||||
# status bar and its SESSION VACANT badge stay — they are the way
|
||||
# back in. To later hide the camera streams as well, add
|
||||
@@ -2860,7 +2860,7 @@ class MainWindow(QMainWindow):
|
||||
self.alert_banner.show_message("Baton acquired!", False, auto_clear_ms=4000)
|
||||
else:
|
||||
self.alert_banner.show_message(
|
||||
"Request declined or cancelled", False, auto_clear_ms=4000
|
||||
"Request declined or canceled", False, auto_clear_ms=4000
|
||||
)
|
||||
|
||||
# Manage incoming request dialog (when someone requests from us)
|
||||
@@ -2896,7 +2896,7 @@ class MainWindow(QMainWindow):
|
||||
self._baton_pending_dialog = BatonPendingDialog(
|
||||
target_user=target_user, timeout_seconds=timeout, parent=self
|
||||
)
|
||||
self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.canceled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.show()
|
||||
else:
|
||||
self._baton_pending_dialog.update_remaining(timeout)
|
||||
@@ -2913,7 +2913,7 @@ class MainWindow(QMainWindow):
|
||||
self._baton_pending_dialog = BatonPendingDialog(
|
||||
target_user="Current Holder", timeout_seconds=0, parent=self
|
||||
)
|
||||
self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.canceled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.show()
|
||||
self._baton_pending_dialog.set_queued_state()
|
||||
|
||||
@@ -2976,7 +2976,7 @@ class MainWindow(QMainWindow):
|
||||
self._baton_pending_dialog = BatonPendingDialog(
|
||||
target_user="Current Holder", timeout_seconds=0, parent=self
|
||||
)
|
||||
self._baton_pending_dialog.cancelled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.canceled_signal.connect(self.daq.cancel_baton_request)
|
||||
self._baton_pending_dialog.show()
|
||||
self._baton_pending_dialog.set_queued_state()
|
||||
|
||||
@@ -3303,7 +3303,7 @@ class MainWindow(QMainWindow):
|
||||
# widgets it inspects — a raise here spams every event and breaks
|
||||
# widget cleanup, so missing attributes must mean "not my click".
|
||||
if event.type() == QEvent.Type.MouseButtonPress:
|
||||
# Non-staff click on the greyed-out Auxiliary-puck tab: only
|
||||
# Non-staff click on the grayed-out Auxiliary-puck tab: only
|
||||
# installed for non-staff, and tabAt() is geometric so it still
|
||||
# sees the disabled tab — explain the lock instead of silently
|
||||
# eating the click.
|
||||
|
||||
@@ -122,7 +122,7 @@ class UserSampleSpreadsheet(QAbstractTableModel):
|
||||
return get_entry(self._sorted_samples[index.row()], index.column())
|
||||
elif role == Qt.ItemDataRole.BackgroundRole:
|
||||
# Status lives in the "#" column, as a full cell fill under the
|
||||
# row number — rows themselves alternate grey/white (view-level)
|
||||
# row number — rows themselves alternate gray/white (view-level)
|
||||
# and selection stays the pale blue tint.
|
||||
if index.column() == COL_STATUS:
|
||||
color = self._status_color(self._sorted_samples[index.row()])
|
||||
@@ -168,7 +168,7 @@ class UserSampleSpreadsheet(QAbstractTableModel):
|
||||
|
||||
@staticmethod
|
||||
def _measured(sample: SampleShortInfo) -> bool:
|
||||
# Automatic status, never relabelled by hand: any rotation data
|
||||
# Automatic status, never relabeled by hand: any rotation data
|
||||
# counts as measured (>= 1); unmeasured is exactly rotation count 0.
|
||||
return isinstance(sample.rotation_count, (int, float)) and sample.rotation_count >= 1
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class AutomationProgressWidget(QWidget):
|
||||
steps_row.setSpacing(6)
|
||||
for step in (
|
||||
WorkflowStateKind.MOUNT,
|
||||
WorkflowStateKind.LOOP_CENTRE,
|
||||
WorkflowStateKind.LOOP_CENTER,
|
||||
WorkflowStateKind.RASTER,
|
||||
WorkflowStateKind.DATA_COLLECTION,
|
||||
):
|
||||
@@ -105,7 +105,7 @@ class AutomationProgressWidget(QWidget):
|
||||
current_step=None,
|
||||
steps=[
|
||||
self._make_step(WorkflowStateKind.MOUNT, StepStatus.PENDING),
|
||||
self._make_step(WorkflowStateKind.LOOP_CENTRE, StepStatus.PENDING),
|
||||
self._make_step(WorkflowStateKind.LOOP_CENTER, StepStatus.PENDING),
|
||||
self._make_step(WorkflowStateKind.RASTER, StepStatus.PENDING),
|
||||
self._make_step(WorkflowStateKind.DATA_COLLECTION, StepStatus.PENDING),
|
||||
self._make_step(WorkflowStateKind.FINAL, StepStatus.PENDING),
|
||||
@@ -128,7 +128,7 @@ class AutomationProgressWidget(QWidget):
|
||||
def _label_for_step(step: WorkflowStateKind) -> str:
|
||||
return {
|
||||
WorkflowStateKind.MOUNT: "Mount",
|
||||
WorkflowStateKind.LOOP_CENTRE: "Center",
|
||||
WorkflowStateKind.LOOP_CENTER: "Center",
|
||||
WorkflowStateKind.RASTER: "Raster",
|
||||
WorkflowStateKind.DATA_COLLECTION: "Collect",
|
||||
WorkflowStateKind.FINAL: "Status",
|
||||
|
||||
@@ -91,7 +91,7 @@ class BeamlineStatePanel(QFrame):
|
||||
|
||||
Replaces the former vertical station map: two-line entries in beamline
|
||||
order, colored by availability (blue/red = active, orange = reachable in
|
||||
one transition, grey = not reachable).
|
||||
one transition, gray = not reachable).
|
||||
"""
|
||||
|
||||
sample_exchange = Signal()
|
||||
@@ -121,7 +121,7 @@ class BeamlineStatePanel(QFrame):
|
||||
(BeamlineStateEnum.XrayFluorescence, "X-ray fluorescence"),
|
||||
)
|
||||
|
||||
# Beam-optics diagnostic states are admin (staff) only: greyed for
|
||||
# Beam-optics diagnostic states are admin (staff) only: grayed for
|
||||
# everyone else, with a red warning tip instead of the routes hint.
|
||||
_STAFF_ONLY_STATES: ClassVar[frozenset[BeamlineStateEnum]] = frozenset(
|
||||
{
|
||||
@@ -135,7 +135,7 @@ class BeamlineStatePanel(QFrame):
|
||||
BeamlineStateEnum.DewarTransfer: "Dewar transfer mode",
|
||||
BeamlineStateEnum.SampleExchange: "Manual sample exchange mode",
|
||||
BeamlineStateEnum.RobotSampleExchange: "Robot-assisted sample exchange",
|
||||
BeamlineStateEnum.SampleAlignment: "Sample centring and alignment mode",
|
||||
BeamlineStateEnum.SampleAlignment: "Sample centering and alignment mode",
|
||||
BeamlineStateEnum.BeamLocation: "Beam location mode",
|
||||
BeamlineStateEnum.BeamstopAlignment: "Beamstop alignment mode",
|
||||
BeamlineStateEnum.FluxMeasurement: "Flux measurement mode",
|
||||
@@ -262,7 +262,7 @@ class BeamlineStatePanel(QFrame):
|
||||
|
||||
def _available_targets(self) -> frozenset[BeamlineStateEnum]:
|
||||
current = self._current_state
|
||||
# Busy greys the whole strip like Moving does: a transition posted
|
||||
# Busy grays the whole strip like Moving does: a transition posted
|
||||
# mid-operation would clobber it (same guard as the status-bar menu).
|
||||
if self._busy or current is None or current == BeamlineStateEnum.Moving:
|
||||
return frozenset()
|
||||
@@ -316,7 +316,7 @@ class BeamlineStatePanel(QFrame):
|
||||
)
|
||||
|
||||
def _emit_for_state(self, state: BeamlineStateEnum) -> None:
|
||||
# Unavailable transitions are not clickable (grey + forbidden cursor).
|
||||
# Unavailable transitions are not clickable (gray + forbidden cursor).
|
||||
if state not in self._available_targets():
|
||||
return
|
||||
self._pending_target_state = state
|
||||
@@ -394,7 +394,7 @@ class BeamlineStatePanel(QFrame):
|
||||
pending_button = button
|
||||
|
||||
# Availability drives the look: active = bold (red for
|
||||
# Maintenance, blue otherwise), reachable = orange, rest = grey.
|
||||
# Maintenance, blue otherwise), reachable = orange, rest = gray.
|
||||
# No backgrounds, no rounded corners.
|
||||
if is_current or is_pending:
|
||||
color = (
|
||||
@@ -422,7 +422,7 @@ class BeamlineStatePanel(QFrame):
|
||||
# cursor under a resting mouse until it moves again.
|
||||
# Hover underline (the app-wide tab/chip affordance) only on
|
||||
# entries that mean something: the current state and reachable
|
||||
# targets — not the grey dead ends.
|
||||
# targets — not the gray dead ends.
|
||||
hover_underline = (
|
||||
" text-decoration: underline;" if (is_current or is_pending or is_available) else ""
|
||||
)
|
||||
|
||||
@@ -373,9 +373,9 @@ class LocalContactPanel(QFrame):
|
||||
)
|
||||
tools_layout.addWidget(
|
||||
self._make_button(
|
||||
"Reinitialise BEC planner/devices",
|
||||
lambda: self._daq.bec_reinitialise_planner_and_position_devices("auto"),
|
||||
"Reinitialising BEC planner and position devices.",
|
||||
"Reinitialize BEC planner/devices",
|
||||
lambda: self._daq.bec_reinitialize_planner_and_position_devices("auto"),
|
||||
"Reinitializing BEC planner and position devices.",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -468,20 +468,20 @@ class LocalContactPanel(QFrame):
|
||||
|
||||
layout.addWidget(
|
||||
self._build_section(
|
||||
"Initialise",
|
||||
"Initialize",
|
||||
[
|
||||
self._make_button(
|
||||
"Initialise detector",
|
||||
self._daq.initialise_detector,
|
||||
"Initialising detector.",
|
||||
"Initialize detector",
|
||||
self._daq.initialize_detector,
|
||||
"Initializing detector.",
|
||||
),
|
||||
self._make_button(
|
||||
"Initialise Smargon", self._daq.initialise_smargon, "Initialising Smargon."
|
||||
"Initialize Smargon", self._daq.initialize_smargon, "Initializing Smargon."
|
||||
),
|
||||
self._make_button(
|
||||
"Initialise Aerotech",
|
||||
self._daq.initialise_aerotech,
|
||||
"Initialising Aerotech.",
|
||||
"Initialize Aerotech",
|
||||
self._daq.initialize_aerotech,
|
||||
"Initializing Aerotech.",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -53,10 +53,10 @@ class RuntimeNotificationWidget(QFrame):
|
||||
self._message.setObjectName("runtimeNotificationMessage")
|
||||
self._message.setWordWrap(True)
|
||||
|
||||
self._minimise_button = QToolButton(self)
|
||||
self._minimise_button.setText("—")
|
||||
self._minimise_button.setToolTip("Minimise notification")
|
||||
self._minimise_button.clicked.connect(self._toggle_minimised)
|
||||
self._minimize_button = QToolButton(self)
|
||||
self._minimize_button.setText("—")
|
||||
self._minimize_button.setToolTip("Minimize notification")
|
||||
self._minimize_button.clicked.connect(self._toggle_minimized)
|
||||
|
||||
self._clear_button = QPushButton("Clear", self)
|
||||
self._clear_button.clicked.connect(self.clear_notification)
|
||||
@@ -67,7 +67,7 @@ class RuntimeNotificationWidget(QFrame):
|
||||
header_layout = QHBoxLayout()
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.addWidget(self._title, 1)
|
||||
header_layout.addWidget(self._minimise_button)
|
||||
header_layout.addWidget(self._minimize_button)
|
||||
|
||||
button_layout = QHBoxLayout()
|
||||
button_layout.setContentsMargins(0, 0, 0, 0)
|
||||
@@ -91,7 +91,7 @@ class RuntimeNotificationWidget(QFrame):
|
||||
|
||||
self._full_title = ""
|
||||
self._full_message = ""
|
||||
self._minimised = False
|
||||
self._minimized = False
|
||||
self._sticky = True
|
||||
|
||||
self.setStyleSheet(
|
||||
@@ -142,11 +142,11 @@ class RuntimeNotificationWidget(QFrame):
|
||||
self.update()
|
||||
|
||||
@Slot()
|
||||
def _toggle_minimised(self) -> None:
|
||||
self._minimised = not self._minimised
|
||||
self._body.setVisible(not self._minimised)
|
||||
self._minimise_button.setText("+" if self._minimised else "—")
|
||||
if self._minimised:
|
||||
def _toggle_minimized(self) -> None:
|
||||
self._minimized = not self._minimized
|
||||
self._body.setVisible(not self._minimized)
|
||||
self._minimize_button.setText("+" if self._minimized else "—")
|
||||
if self._minimized:
|
||||
self._title.setText(self._full_title or "Notification")
|
||||
else:
|
||||
self._title.setText(self._full_title)
|
||||
@@ -170,8 +170,8 @@ class RuntimeNotificationWidget(QFrame):
|
||||
self._message.setText(self._full_message)
|
||||
self._clear_button.setVisible(not sticky)
|
||||
self._body.setVisible(True)
|
||||
self._minimised = False
|
||||
self._minimise_button.setText("—")
|
||||
self._minimized = False
|
||||
self._minimize_button.setText("—")
|
||||
self.setVisible(True)
|
||||
|
||||
if not sticky:
|
||||
|
||||
@@ -52,12 +52,12 @@ logger = setup_logger(LOGGER_NAME)
|
||||
# LED step indicator
|
||||
# ---------------------------------------------------------------------------
|
||||
class LEDStages(QWidget):
|
||||
STEPS: ClassVar[list[str]] = ["Mount", "Centre", "Raster", "Collect"]
|
||||
STEPS: ClassVar[list[str]] = ["Mount", "Center", "Raster", "Collect"]
|
||||
|
||||
# WorkflowStateKind → LED index
|
||||
_KIND_TO_INDEX: ClassVar[dict[WorkflowStateKind, int]] = {
|
||||
WorkflowStateKind.MOUNT: 0,
|
||||
WorkflowStateKind.LOOP_CENTRE: 1,
|
||||
WorkflowStateKind.LOOP_CENTER: 1,
|
||||
WorkflowStateKind.RASTER: 2,
|
||||
WorkflowStateKind.DATA_COLLECTION: 3,
|
||||
}
|
||||
@@ -360,7 +360,7 @@ class PortraitModePanel(QWidget):
|
||||
self._leds = LEDStages(active_step=0)
|
||||
layout.addWidget(self._leds)
|
||||
|
||||
# Play/Pause button (single, centred)
|
||||
# Play/Pause button (single, centered)
|
||||
ctrl_frame = QFrame()
|
||||
ctrl_frame.setStyleSheet(f"QFrame {{ background: {CARD_BG}; border-radius: 18px; }}")
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ class SamcamPanel(QWidget):
|
||||
|
||||
# Target color
|
||||
target_color_layout = QHBoxLayout()
|
||||
target_color_label = QLabel("Target colour:")
|
||||
target_color_label = QLabel("Target color:")
|
||||
self.target_color_combo = QComboBox()
|
||||
self.target_color_combo.addItems(["Cyan", "Dark Blue", "Dark Red"])
|
||||
self.target_color_combo.setCurrentText("Cyan")
|
||||
|
||||
@@ -200,7 +200,7 @@ class TellSamplePanel(QFrame):
|
||||
lambda chip: self.table_model.set_status_filter(chip.property("status_key"))
|
||||
)
|
||||
|
||||
# Staggered grey/white rows tell rows apart — no grid lines, no row
|
||||
# Staggered gray/white rows tell rows apart — no grid lines, no row
|
||||
# tints; status fills the frozen "#" column and selection stays blue.
|
||||
self.table_view = FrozenColumnTableView()
|
||||
self.table_view.setShowGrid(False)
|
||||
|
||||
@@ -51,7 +51,7 @@ _VIRIDIS_COLORS = [
|
||||
(253, 231, 37), # Yellow
|
||||
]
|
||||
|
||||
# Float (N, 3) lookup table for vectorised colour mapping.
|
||||
# Float (N, 3) lookup table for vectorised color mapping.
|
||||
_VIRIDIS_LUT = np.array(_VIRIDIS_COLORS, dtype=np.float64)
|
||||
|
||||
|
||||
@@ -551,7 +551,7 @@ class RasterGridManager(QObject):
|
||||
self, cache_key: tuple, grid: RasterGridRequest, values: list[float] | list[int]
|
||||
) -> QImage | None:
|
||||
"""Return a cached n_x*n_y heatmap bitmap for this grid, building it once
|
||||
on a cache miss. One pixel per cell; colours baked at full opacity with
|
||||
on a cache miss. One pixel per cell; colors baked at full opacity with
|
||||
the alpha channel encoding validity (overlay transparency is applied at
|
||||
blit time via painter opacity, so it never invalidates the cache)."""
|
||||
cached = self._heatmap_cache.get(cache_key)
|
||||
@@ -651,7 +651,7 @@ class RasterGridManager(QObject):
|
||||
painter.drawRect(bounds)
|
||||
painter.restore()
|
||||
|
||||
# TODO make sure draw_grid is visualising the grid correctly, correct orientation, correct x/y labelling!!!!
|
||||
# TODO make sure draw_grid is visualizing the grid correctly, correct orientation, correct x/y labelling!!!!
|
||||
def _draw_grid(
|
||||
self,
|
||||
painter: QPainter,
|
||||
@@ -920,7 +920,7 @@ class RasterGridManager(QObject):
|
||||
self._active_grid.n_y = 0
|
||||
self._invalidate_heatmap_cache()
|
||||
if last_raster is not None and last_raster.result.file_prefix is not None:
|
||||
com = last_raster.centre_of_mass
|
||||
com = last_raster.center_of_mass
|
||||
logger.info(f"COM: {com}")
|
||||
cell = com.max_image if com else 0
|
||||
self.image_selected.emit(self._detector_url, cell)
|
||||
|
||||
@@ -23,7 +23,7 @@ THEME_BLUEBIRD = "bluebird"
|
||||
# -- Light theme ------------------------------------------------------------
|
||||
BACKGROUND = "#e2e7ee"
|
||||
# App-wide sunrise-sky gradient (sampled from the reference photo taken at dawn
|
||||
# near Dawn's house at Windisch: slate blue fading through pale grey-lavender
|
||||
# near Dawn's house at Windisch: slate blue fading through pale gray-lavender
|
||||
# into warm cream. Painted once per top-level window (QMainWindow/QDialog)
|
||||
# while plain child widgets stay transparent, so the window reads as ONE
|
||||
# continuous sky instead of every widget restarting the gradient.
|
||||
@@ -117,7 +117,7 @@ BANNER_TAB_GAP = 6
|
||||
# one for SEPARATOR_HINT_DELAY_MS (or a drag starts) — then only the exact
|
||||
# separator under the cursor fills with SEPARATOR_HINT. The rest/drag gate
|
||||
# lives in MainWindow.event(); the QSS :hover part picks the one separator.
|
||||
SEPARATOR_HINT = "rgba(168, 178, 192, 20%)" # scrollbar-track grey @50%
|
||||
SEPARATOR_HINT = "rgba(168, 178, 192, 20%)" # scrollbar-track gray @50%
|
||||
SEPARATOR_HINT_DELAY_MS = 888 # int, used in code, not QSS
|
||||
|
||||
# Theme-switch screenshot cross-fade duration (int ms, used in code).
|
||||
@@ -444,7 +444,7 @@ TABLE_SHADE_BG = "#e0e0e0"
|
||||
# -- Sample status row tints (dewar/queue view) -----------------------------
|
||||
# Status colors now fill the rounded dot in the table's status column; rows
|
||||
# themselves alternate WHITE / SAMPLE_ROW_ALT_BG. Tune the palette here.
|
||||
SAMPLE_ROW_ALT_BG = "#eef1f5" # staggered row grey (alternates with white)
|
||||
SAMPLE_ROW_ALT_BG = "#eef1f5" # staggered row gray (alternates with white)
|
||||
SAMPLE_STATUS_QUEUED_BG = "#ffe4c4" # pale orange — waiting in the automation queue
|
||||
SAMPLE_STATUS_FLAGGED_BG = "#ffd9d9" # pale red — automation failed on this sample
|
||||
SAMPLE_STATUS_MEASURED_BG = "#dcf2e0" # pale green — already has collected data
|
||||
@@ -466,7 +466,7 @@ PATH_END = "#d20f39" # raster path gradient end + end circle (red)
|
||||
LEGEND_BG = "#eff1f5" # base
|
||||
LEGEND_TEXT = "#4c4f69" # text
|
||||
TOOLTIP_TEXT = "#4c4f69" # camera coords tooltip pen — NOT the QToolTip popup
|
||||
SCALE_BAR_GREY = "#8c8fa1" # hover HUD scale bar (Latte overlay1 grey)
|
||||
SCALE_BAR_GRAY = "#8c8fa1" # hover HUD scale bar (Latte overlay1 gray)
|
||||
MARK_TOOLTIP_GOLD = "#df8e1d" # yellow
|
||||
MARK_TOOLTIP_ORANGE = "#fe640b" # peach
|
||||
MARK_TOOLTIP_RED = "#d20f39" # red
|
||||
@@ -587,7 +587,7 @@ def admin_tip_qss(theme: str) -> str:
|
||||
SLIDER_FILL = "#8ba3c7"
|
||||
|
||||
# -- Scrollbars (rounded, no arrows) ----------------------------------------
|
||||
# Flipped on request: the track is now the darker grey and the draggable
|
||||
# Flipped on request: the track is now the darker gray and the draggable
|
||||
# handle the light one; hover therefore lightens further instead of darkening.
|
||||
SCROLLBAR_TRACK = "#E4E4E4"
|
||||
SCROLLBAR_HANDLE = "#D4D4D4"
|
||||
@@ -998,7 +998,7 @@ def _sunrise_stylesheet(overrides: dict[str, str] | None = None) -> str:
|
||||
}
|
||||
|
||||
/* Disabled = baton-gated ("watch only"): the explicit colors above mask
|
||||
Qt's native grey, so spell the greyed state out. */
|
||||
Qt's native gray, so spell the grayed state out. */
|
||||
QPushButton:disabled, QCheckBox:disabled, QRadioButton:disabled,
|
||||
QLabel:disabled, QComboBox:disabled, QLineEdit:disabled,
|
||||
QAbstractSpinBox:disabled, QTabBar::tab:disabled {
|
||||
@@ -1179,7 +1179,7 @@ def _sunrise_stylesheet(overrides: dict[str, str] | None = None) -> str:
|
||||
}
|
||||
|
||||
/* Pale-blue selection with readable dark text in every sample table;
|
||||
staggered grey/white rows where alternation is enabled. */
|
||||
staggered gray/white rows where alternation is enabled. */
|
||||
QTableView {
|
||||
background: $white;
|
||||
alternate-background-color: $sample_row_alt_bg;
|
||||
|
||||
@@ -1129,7 +1129,7 @@ class DAQWorker(QObject):
|
||||
raster_elem = CompletedRasterGridElem(
|
||||
request=new_copy,
|
||||
result=ScanResult(file_prefix=r.file_prefix, images=images),
|
||||
centre_of_mass=None,
|
||||
center_of_mass=None,
|
||||
)
|
||||
reply = CompletedRasterGrid(r=[raster_elem])
|
||||
self.raster_scan_completed.emit(reply)
|
||||
@@ -1171,7 +1171,7 @@ class DAQWorker(QObject):
|
||||
raster_elem = CompletedRasterGridElem(
|
||||
request=new_copy,
|
||||
result=ScanResult(file_prefix=r.file_prefix, images=images),
|
||||
centre_of_mass=None,
|
||||
center_of_mass=None,
|
||||
)
|
||||
reply = CompletedRasterGrid(r=[raster_elem])
|
||||
self.raster_scan_completed.emit(reply)
|
||||
@@ -1727,8 +1727,8 @@ class DAQWorker(QObject):
|
||||
self.http_error.emit(str(e))
|
||||
|
||||
@Slot(str)
|
||||
def bec_reinitialise_planner_and_position_devices(self, method: str = "auto"):
|
||||
self.generic_post(f"bec/reinitialise_planner_and_position_devices?method={method}")
|
||||
def bec_reinitialize_planner_and_position_devices(self, method: str = "auto"):
|
||||
self.generic_post(f"bec/reinitialize_planner_and_position_devices?method={method}")
|
||||
|
||||
@Slot()
|
||||
def bec_save_current_bs_pos(self):
|
||||
@@ -1743,7 +1743,7 @@ class DAQWorker(QObject):
|
||||
self.generic_post("bec/save_current_aerotech_position")
|
||||
|
||||
@Slot()
|
||||
def initialise_smargon(self):
|
||||
def initialize_smargon(self):
|
||||
self.generic_post("smargon/initialize")
|
||||
|
||||
@Slot()
|
||||
@@ -1751,7 +1751,7 @@ class DAQWorker(QObject):
|
||||
self.generic_post("beamline/save_beam_location_camera_setting")
|
||||
|
||||
@Slot()
|
||||
def initialise_aerotech(self):
|
||||
def initialize_aerotech(self):
|
||||
logger.info("initisalisation does not initisalise aareSCAN but runs homing script")
|
||||
self.generic_post("aerotech/initialize")
|
||||
|
||||
@@ -1760,7 +1760,7 @@ class DAQWorker(QObject):
|
||||
self.generic_post("detector/take_pedestal")
|
||||
|
||||
@Slot()
|
||||
def initialise_detector(self):
|
||||
def initialize_detector(self):
|
||||
self.generic_post("detector/initialize")
|
||||
|
||||
@Slot()
|
||||
|
||||
@@ -28,7 +28,7 @@ class ControlsHelpDialog(QDialog):
|
||||
<h3>Mouse Click / Drag</h3>
|
||||
<ul>
|
||||
<li><b>Left click</b>: move sample to clicked position</li>
|
||||
<li><b>Shift + Left click</b>: move using the special Z-alignment click behaviour</li>
|
||||
<li><b>Shift + Left click</b>: move using the special Z-alignment click behavior</li>
|
||||
<li><b>Ctrl + Left click on active raster grid</b>: move to the clicked position under the grid</li>
|
||||
<li><b>Left drag on active raster grid</b>: move active raster grid</li>
|
||||
<li><b>Right click</b>: open sample camera context menu</li>
|
||||
@@ -87,7 +87,7 @@ class ControlsHelpDialog(QDialog):
|
||||
<ul>
|
||||
<li><b>Ctrl + Mouse wheel</b>: zoom in/out</li>
|
||||
<li><b>Mouse wheel</b>: normal scrolling when Ctrl is not pressed</li>
|
||||
<li><b>Mouse drag</b>: rubber-band drag/selection behaviour is enabled</li>
|
||||
<li><b>Mouse drag</b>: rubber-band drag/selection behavior is enabled</li>
|
||||
</ul>
|
||||
|
||||
<h3>Keyboard</h3>
|
||||
|
||||
@@ -85,7 +85,7 @@ class TutorialOverlay(QWidget):
|
||||
next_requested = Signal()
|
||||
back_requested = Signal()
|
||||
skip_requested = Signal()
|
||||
cancelled = Signal()
|
||||
canceled = Signal()
|
||||
highlight_clicked = Signal()
|
||||
|
||||
def __init__(self, parent: QWidget | None = None):
|
||||
@@ -146,7 +146,7 @@ class TutorialOverlay(QWidget):
|
||||
self.end_button = QPushButton("End tutorial", self)
|
||||
self.end_button.setStyleSheet(button_style)
|
||||
self.end_button.setMinimumHeight(44)
|
||||
self.end_button.clicked.connect(self.cancelled.emit)
|
||||
self.end_button.clicked.connect(self.canceled.emit)
|
||||
self.end_button.hide()
|
||||
|
||||
self.hide()
|
||||
@@ -178,7 +178,7 @@ class TutorialOverlay(QWidget):
|
||||
|
||||
def keyPressEvent(self, event) -> None:
|
||||
if event.key() == Qt.Key_Escape:
|
||||
self.cancelled.emit()
|
||||
self.canceled.emit()
|
||||
event.accept()
|
||||
return
|
||||
super().keyPressEvent(event)
|
||||
@@ -386,7 +386,7 @@ class TutorialManager(QObject):
|
||||
self.overlay.next_requested.connect(self._on_next_requested)
|
||||
self.overlay.back_requested.connect(self._on_back_requested)
|
||||
self.overlay.skip_requested.connect(self._on_skip_requested)
|
||||
self.overlay.cancelled.connect(self.stop)
|
||||
self.overlay.canceled.connect(self.stop)
|
||||
self.overlay.highlight_clicked.connect(self._on_highlight_clicked)
|
||||
|
||||
self.event_bus.event_emitted.connect(self._on_tutorial_event)
|
||||
|
||||
@@ -56,7 +56,7 @@ class CompactAutomationProgressStrip(QFrame):
|
||||
|
||||
for step in (
|
||||
WorkflowStateKind.MOUNT,
|
||||
WorkflowStateKind.LOOP_CENTRE,
|
||||
WorkflowStateKind.LOOP_CENTER,
|
||||
WorkflowStateKind.RASTER,
|
||||
WorkflowStateKind.DATA_COLLECTION,
|
||||
WorkflowStateKind.FINAL,
|
||||
@@ -79,7 +79,7 @@ class CompactAutomationProgressStrip(QFrame):
|
||||
def _step_title(step: WorkflowStateKind) -> str:
|
||||
return {
|
||||
WorkflowStateKind.MOUNT: "Mount",
|
||||
WorkflowStateKind.LOOP_CENTRE: "Center",
|
||||
WorkflowStateKind.LOOP_CENTER: "Center",
|
||||
WorkflowStateKind.RASTER: "Raster",
|
||||
WorkflowStateKind.DATA_COLLECTION: "Collect",
|
||||
WorkflowStateKind.FINAL: "Finish",
|
||||
|
||||
@@ -238,7 +238,7 @@ class BatonPendingDialog(QDialog):
|
||||
or for the beamline queue to clear.
|
||||
"""
|
||||
|
||||
cancelled_signal = Signal()
|
||||
canceled_signal = Signal()
|
||||
|
||||
def __init__(self, target_user: str, timeout_seconds: int = 30, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -361,5 +361,5 @@ class BatonPendingDialog(QDialog):
|
||||
# Keep cancel button so they can abort the wait if they change their mind
|
||||
|
||||
def _on_cancel(self):
|
||||
self.cancelled_signal.emit()
|
||||
self.canceled_signal.emit()
|
||||
self.reject()
|
||||
|
||||
@@ -56,7 +56,7 @@ from aare.gui.styles import (
|
||||
MARKER_GREEN,
|
||||
PATH_END,
|
||||
PATH_START,
|
||||
SCALE_BAR_GREY,
|
||||
SCALE_BAR_GRAY,
|
||||
SHADOW,
|
||||
TARGET_COLORS,
|
||||
THEME_SUNSET,
|
||||
@@ -1297,7 +1297,7 @@ class SampleCameraImageLabel(QGraphicsView):
|
||||
return bar_um, label
|
||||
|
||||
def _draw_hover_hud(self, painter: QPainter):
|
||||
# Bottom-right HUD: grey scale bar over the hovered pixel coordinates.
|
||||
# Bottom-right HUD: gray scale bar over the hovered pixel coordinates.
|
||||
if self._hover_pos is None or self.pixmap_item is None:
|
||||
return
|
||||
if not self.pixmap_item.sceneBoundingRect().contains(self._hover_pos):
|
||||
@@ -1317,7 +1317,7 @@ class SampleCameraImageLabel(QGraphicsView):
|
||||
right = self.viewport().width() - margin
|
||||
coords_text = f"{self._hover_pos.x():.0f}, {self._hover_pos.y():.0f} pxl"
|
||||
coords_baseline = self.viewport().height() - margin - fm.descent()
|
||||
grey = qcolor(SCALE_BAR_GREY)
|
||||
gray = qcolor(SCALE_BAR_GRAY)
|
||||
|
||||
def shadowed_text(x: float, baseline: float, text: str, color: QColor):
|
||||
painter.setPen(QPen(qcolor(SHADOW, 200)))
|
||||
@@ -1336,12 +1336,12 @@ class SampleCameraImageLabel(QGraphicsView):
|
||||
bar_um, label = self._scale_bar(um_per_view_px)
|
||||
bar_px = bar_um / um_per_view_px
|
||||
bar_y = coords_baseline - fm.ascent() - 12
|
||||
painter.setPen(QPen(grey, 3))
|
||||
painter.setPen(QPen(gray, 3))
|
||||
painter.drawLine(QPointF(right - bar_px, bar_y), QPointF(right, bar_y))
|
||||
painter.drawLine(QPointF(right - bar_px, bar_y - 4), QPointF(right - bar_px, bar_y + 4))
|
||||
painter.drawLine(QPointF(right, bar_y - 4), QPointF(right, bar_y + 4))
|
||||
shadowed_text(
|
||||
right - (bar_px + fm.horizontalAdvance(label)) / 2, bar_y - 8, label, grey
|
||||
right - (bar_px + fm.horizontalAdvance(label)) / 2, bar_y - 8, label, gray
|
||||
)
|
||||
|
||||
painter.restore()
|
||||
|
||||
@@ -73,7 +73,7 @@ class LocalContactStatusWidget(QFrame):
|
||||
"dtz": "Detector distance",
|
||||
"energy": "Energy",
|
||||
"wavelength": "Wavelength",
|
||||
"beam_center": "Beam centre",
|
||||
"beam_center": "Beam center",
|
||||
}
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -51,7 +51,7 @@ class NumberLineEdit(QLineEdit):
|
||||
|
||||
@Slot(str)
|
||||
def on_text_changed(self, text: str):
|
||||
# when text changes check validation and change the colour of the line edit
|
||||
# when text changes check validation and change the color of the line edit
|
||||
self._is_valid = self.validate(text)
|
||||
self._set_invalid(not self._is_valid)
|
||||
|
||||
@@ -156,13 +156,13 @@ class CheckedLineEdit(QWidget):
|
||||
|
||||
def set_busy(self, busy: bool):
|
||||
# if an external wants to change the busy state.
|
||||
# update self._busy and change editor read only state. After enable/disable check_box and set colour
|
||||
# update self._busy and change editor read only state. After enable/disable check_box and set color
|
||||
self.blockSignals(True)
|
||||
self._busy = busy
|
||||
self.setReadOnly()
|
||||
self.check_box.blockSignals(True)
|
||||
|
||||
# No inline checkbox fills: the theme's :disabled rules grey it.
|
||||
# No inline checkbox fills: the theme's :disabled rules gray it.
|
||||
if self._busy:
|
||||
self.check_box.setEnabled(False)
|
||||
if self._checked:
|
||||
@@ -232,7 +232,7 @@ class DbOverrideLineEdit(QWidget):
|
||||
"""A numeric field backed by two sources: a database value and the user's
|
||||
own value, with a panel-level toggle choosing which is shown.
|
||||
|
||||
Behaviour:
|
||||
Behavior:
|
||||
* Until the user edits the field, "mine" mirrors the database value, so a
|
||||
fresh field just follows the database.
|
||||
* Editing records the user's value, marks the field as user-edited, flips
|
||||
|
||||
@@ -542,7 +542,7 @@ class StatusBar(QStatusBar):
|
||||
if self._is_staff:
|
||||
action_4.triggered.connect(self.beam_location)
|
||||
else:
|
||||
# Same gate as the state strip: greyed, not hidden, so
|
||||
# Same gate as the state strip: grayed, not hidden, so
|
||||
# non-staff learn the state exists but needs admin mode.
|
||||
action_4.setText("Beam location (admin mode only)")
|
||||
action_4.setEnabled(False)
|
||||
@@ -590,7 +590,7 @@ class StatusBar(QStatusBar):
|
||||
}
|
||||
if not merged:
|
||||
merged = set(pgroups)
|
||||
self._generate_pgroup_dialogue(curr=curr, pgroups=sorted(merged))
|
||||
self._generate_pgroup_dialog(curr=curr, pgroups=sorted(merged))
|
||||
finally:
|
||||
try:
|
||||
self.staff_pgroups_loaded.disconnect(_on_loaded)
|
||||
@@ -601,7 +601,7 @@ class StatusBar(QStatusBar):
|
||||
self._list_staff_pgroups()
|
||||
return
|
||||
|
||||
self._generate_pgroup_dialogue(curr=curr, pgroups=pgroups)
|
||||
self._generate_pgroup_dialog(curr=curr, pgroups=pgroups)
|
||||
|
||||
def _on_grab_clicked(self):
|
||||
"""Handle grab/request click - baton first, p-group after grant."""
|
||||
@@ -644,7 +644,7 @@ class StatusBar(QStatusBar):
|
||||
def _list_staff_pgroups(self):
|
||||
self.get_all_pgroups.emit()
|
||||
|
||||
def _generate_pgroup_dialogue(self, curr: str | None = None, pgroups: list | None = None):
|
||||
def _generate_pgroup_dialog(self, curr: str | None = None, pgroups: list | None = None):
|
||||
# logger.info(pgroups) # too much information for normal operation
|
||||
dialog = PGroupDialog(curr_pgroup=curr, pgroups=pgroups, parent=self.window())
|
||||
|
||||
@@ -658,6 +658,6 @@ class StatusBar(QStatusBar):
|
||||
f"P-group '{entered_text}' is not in your allowed list.\n"
|
||||
f"Please select from: {', '.join(pgroups)}",
|
||||
)
|
||||
self._generate_pgroup_dialogue(curr=curr, pgroups=pgroups)
|
||||
self._generate_pgroup_dialog(curr=curr, pgroups=pgroups)
|
||||
return
|
||||
self.set_pgroup.emit(entered_text)
|
||||
|
||||
@@ -71,7 +71,7 @@ class TitleLabel(QLabel):
|
||||
f"QPushButton {{ background: transparent; border: none;"
|
||||
f" color: {BANNER_TEXT}; font-size: {FONT_VALUE}; font-weight: 700; }}"
|
||||
)
|
||||
self.toggle_button.setToolTip("Minimise panel")
|
||||
self.toggle_button.setToolTip("Minimize panel")
|
||||
self.toggle_button.setFixedSize(21, 21)
|
||||
self.toggle_button.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.toggle_button.clicked.connect(self.toggle_collapsed)
|
||||
@@ -162,7 +162,7 @@ class TitleLabel(QLabel):
|
||||
return
|
||||
self._set_visible(parent_layout, not self._collapsed)
|
||||
self.toggle_button.setText("+" if self._collapsed else "−")
|
||||
self.toggle_button.setToolTip("Restore panel" if self._collapsed else "Minimise panel")
|
||||
self.toggle_button.setToolTip("Restore panel" if self._collapsed else "Minimize panel")
|
||||
|
||||
def _set_visible(self, layout: QLayout, visible: bool) -> None:
|
||||
# Recursive: panels like SamcamPanel nest sub-layouts via addLayout.
|
||||
|
||||
@@ -201,14 +201,14 @@ def test_service_falls_back_to_loop_all_when_face_ratio_is_low(monkeypatch, cont
|
||||
assert context._progress_events[-1]["running"] is False
|
||||
|
||||
|
||||
def test_service_applies_centre_correction_when_target_is_far_from_beam(
|
||||
def test_service_applies_center_correction_when_target_is_far_from_beam(
|
||||
monkeypatch, context, mock_logger
|
||||
):
|
||||
service = FaceDetectionService(context=context, logger=mock_logger)
|
||||
|
||||
model = _box(MLBoxType.LOOP_FACE, 40, 160, 80, 200)
|
||||
|
||||
service._centre_correction(model, tolerance=0.2)
|
||||
service._center_correction(model, tolerance=0.2)
|
||||
|
||||
assert isinstance(context.deps.devs.smargon_pos, SmargonCoordinate)
|
||||
assert context.deps.devs.smargon_pos.sh_mm.x == pytest.approx(1.0)
|
||||
|
||||
@@ -96,7 +96,7 @@ def test_record_best_effort_step_failure_marks_progress_and_logs_warning(mock_lo
|
||||
current_step="Center",
|
||||
steps=[
|
||||
StepState(
|
||||
step=WorkflowStateKind.LOOP_CENTRE, status=StepStatus.RUNNING, message="Centering"
|
||||
step=WorkflowStateKind.LOOP_CENTER, status=StepStatus.RUNNING, message="Centering"
|
||||
)
|
||||
],
|
||||
finished=False,
|
||||
@@ -116,7 +116,7 @@ def test_record_best_effort_step_failure_marks_progress_and_logs_warning(mock_lo
|
||||
with patch("aare.daq.daq.logger", mock_logger):
|
||||
daq._record_best_effort_step_failure(
|
||||
progress=progress,
|
||||
step=WorkflowStateKind.LOOP_CENTRE,
|
||||
step=WorkflowStateKind.LOOP_CENTER,
|
||||
error=LoopCenteringFailed("Loop centering failed"),
|
||||
sample=sample,
|
||||
code="LOOP_CENTERING_FAILED",
|
||||
|
||||
@@ -300,7 +300,7 @@ def test_cancel_baton_request(mock_cfg, token_data):
|
||||
status=BatonRequestStatus.PENDING,
|
||||
)
|
||||
res = cancel_baton_request(mock_cfg, token_data)
|
||||
assert res["cancelled"] is True
|
||||
assert res["canceled"] is True
|
||||
mock_cfg.clear_pending_baton_request.assert_called_once()
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ def test_automation_progress_state_round_trip_dataclass():
|
||||
step=WorkflowStateKind.MOUNT, status=StepStatus.SUCCESS, message="Mount complete"
|
||||
),
|
||||
StepState(
|
||||
step=WorkflowStateKind.LOOP_CENTRE,
|
||||
step=WorkflowStateKind.LOOP_CENTER,
|
||||
status=StepStatus.RUNNING,
|
||||
message="Centering sample",
|
||||
),
|
||||
|
||||
@@ -66,67 +66,67 @@ def make_service() -> RasterService:
|
||||
return RasterService(context=context, logger=MagicMock())
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_single_cell():
|
||||
def test_grid_image_id_from_center_offset_single_cell():
|
||||
request = make_request(1, 1)
|
||||
image_id = RasterService._grid_image_id_from_centre_offset(
|
||||
image_id = RasterService._grid_image_id_from_center_offset(
|
||||
x_mm=request.grid_size_mm.x / 2.0, y_mm=request.grid_size_mm.y / 2.0, request=request
|
||||
)
|
||||
assert image_id == 0
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_odd_grid():
|
||||
def test_grid_image_id_from_center_offset_odd_grid():
|
||||
request = make_request(5, 3, cell_x=0.01, cell_y=0.02)
|
||||
|
||||
x_mm = ((request.n_x - 1) * request.grid_size_mm.x) / 2.0
|
||||
y_mm = ((request.n_y - 1) * request.grid_size_mm.y) / 2.0
|
||||
|
||||
image_id = RasterService._grid_image_id_from_centre_offset(
|
||||
image_id = RasterService._grid_image_id_from_center_offset(
|
||||
x_mm=x_mm, y_mm=y_mm, request=request
|
||||
)
|
||||
|
||||
assert image_id == 7
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_even_grid():
|
||||
def test_grid_image_id_from_center_offset_even_grid():
|
||||
request = make_request(4, 4, cell_x=0.01, cell_y=0.01)
|
||||
|
||||
x_mm = ((request.n_x - 1) * request.grid_size_mm.x) / 2.0
|
||||
y_mm = ((request.n_y - 1) * request.grid_size_mm.y) / 2.0
|
||||
|
||||
image_id = RasterService._grid_image_id_from_centre_offset(
|
||||
image_id = RasterService._grid_image_id_from_center_offset(
|
||||
x_mm=x_mm, y_mm=y_mm, request=request
|
||||
)
|
||||
|
||||
assert image_id == 6
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_vertical_scan():
|
||||
def test_grid_image_id_from_center_offset_vertical_scan():
|
||||
request = make_request(1, 50, cell_x=0.01, cell_y=0.005)
|
||||
|
||||
x_mm = request.grid_size_mm.x / 2.0
|
||||
y_mm = ((request.n_y - 1) * request.grid_size_mm.y) / 2.0
|
||||
|
||||
image_id = RasterService._grid_image_id_from_centre_offset(
|
||||
image_id = RasterService._grid_image_id_from_center_offset(
|
||||
x_mm=x_mm, y_mm=y_mm, request=request
|
||||
)
|
||||
|
||||
assert image_id == 24
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_rejects_non_positive_cell_size():
|
||||
def test_grid_image_id_from_center_offset_rejects_non_positive_cell_size():
|
||||
request = make_request(3, 3)
|
||||
request.grid_size_mm = Coordinate(x=0.0, y=0.01)
|
||||
|
||||
with pytest.raises(ValueError, match="grid_size_mm must be positive"):
|
||||
RasterService._grid_image_id_from_centre_offset(x_mm=0.0, y_mm=0.0, request=request)
|
||||
RasterService._grid_image_id_from_center_offset(x_mm=0.0, y_mm=0.0, request=request)
|
||||
|
||||
|
||||
def test_grid_image_id_from_centre_offset_rejects_zero_dimensions():
|
||||
def test_grid_image_id_from_center_offset_rejects_zero_dimensions():
|
||||
request = make_request(1, 1)
|
||||
request.n_x = 0
|
||||
|
||||
with pytest.raises(ValueError, match="Raster grid dimensions must be >= 1"):
|
||||
RasterService._grid_image_id_from_centre_offset(x_mm=0.0, y_mm=0.0, request=request)
|
||||
RasterService._grid_image_id_from_center_offset(x_mm=0.0, y_mm=0.0, request=request)
|
||||
|
||||
|
||||
def test_upload_raster_diffraction_preview_skips_out_of_range_image_id():
|
||||
|
||||
@@ -28,7 +28,7 @@ def test_parse_automation_progress_from_sse_payload():
|
||||
"message": "Mount complete",
|
||||
},
|
||||
{
|
||||
"step": WorkflowStateKind.LOOP_CENTRE.value,
|
||||
"step": WorkflowStateKind.LOOP_CENTER.value,
|
||||
"status": StepStatus.RUNNING.value,
|
||||
"message": "Centering sample",
|
||||
},
|
||||
@@ -64,7 +64,7 @@ def test_parse_automation_progress_from_sse_payload():
|
||||
assert progress.steps[0].status == StepStatus.SUCCESS
|
||||
assert progress.steps[0].message == "Mount complete"
|
||||
|
||||
assert progress.steps[1].step == WorkflowStateKind.LOOP_CENTRE
|
||||
assert progress.steps[1].step == WorkflowStateKind.LOOP_CENTER
|
||||
assert progress.steps[1].status == StepStatus.RUNNING
|
||||
assert progress.steps[1].message == "Centering sample"
|
||||
|
||||
@@ -110,7 +110,7 @@ def test_parse_automation_progress_parses_events():
|
||||
"exception_class": "LoopCenteringFailed",
|
||||
"message": "Loop centering failed",
|
||||
"sample_id": 42,
|
||||
"context": {"step": "loop_centre"},
|
||||
"context": {"step": "loop_center"},
|
||||
}
|
||||
],
|
||||
"finished": False,
|
||||
@@ -132,7 +132,7 @@ def test_handle_automation_progress_event_dedups_events_by_timestamp(caplog):
|
||||
'{"seq":1,"progress":{"current_step":"Center","steps":[],"events":['
|
||||
'{"ts":"2026-06-03T10:00:00+00:00","level":"WARNING","code":"LOOP_CENTERING_FAILED",'
|
||||
'"exception_class":"LoopCenteringFailed","message":"Loop centering failed","sample_id":7,'
|
||||
'"context":{"step":"loop_centre"}}],"finished":false,"success":null}}'
|
||||
'"context":{"step":"loop_center"}}],"finished":false,"success":null}}'
|
||||
)
|
||||
|
||||
caplog.clear()
|
||||
@@ -158,7 +158,7 @@ def test_handle_automation_progress_event_trips_recurrence_watcher():
|
||||
'{"seq":1,"progress":{"current_step":"Center","steps":[],"events":['
|
||||
'{"ts":"2026-06-03T10:00:00+00:00","level":"WARNING","code":"LOOP_CENTERING_FAILED",'
|
||||
'"exception_class":"LoopCenteringFailed","message":"Loop centering failed","sample_id":7,'
|
||||
'"context":{"step":"loop_centre"}}],"finished":false,"success":null}}'
|
||||
'"context":{"step":"loop_center"}}],"finished":false,"success":null}}'
|
||||
)
|
||||
|
||||
worker._handle_automation_progress_event(payload)
|
||||
@@ -202,7 +202,7 @@ def test_process_automation_progress_buffer_handles_split_sse_event():
|
||||
|
||||
first_chunk = 'data: {"seq":1,"progress":{"current_step":"Center","steps":[{"step":"mount",'
|
||||
second_chunk = (
|
||||
'"status":"success","message":"Mount complete"},{"step":"loop_centre",'
|
||||
'"status":"success","message":"Mount complete"},{"step":"loop_center",'
|
||||
'"status":"running","message":"Centering sample"}],'
|
||||
'"finished":false,"success":null}}\n\n'
|
||||
)
|
||||
@@ -224,7 +224,7 @@ def test_process_automation_progress_buffer_handles_split_sse_event():
|
||||
assert len(progress.steps) == 2
|
||||
assert progress.steps[0].step == WorkflowStateKind.MOUNT
|
||||
assert progress.steps[0].status == StepStatus.SUCCESS
|
||||
assert progress.steps[1].step == WorkflowStateKind.LOOP_CENTRE
|
||||
assert progress.steps[1].step == WorkflowStateKind.LOOP_CENTER
|
||||
assert progress.steps[1].status == StepStatus.RUNNING
|
||||
assert worker._automation_progress_buffer == ""
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_non_staff_never_reach_admin_only_states(qtbot):
|
||||
assert BeamlineStateEnum.BeamstopAlignment not in targets
|
||||
assert BeamlineStateEnum.FluxMeasurement not in targets
|
||||
assert BeamlineStateEnum.DataCollection in targets # non-admin route stays
|
||||
# Greyed like unreachable states, and the warning tip carries the red
|
||||
# Grayed like unreachable states, and the warning tip carries the red
|
||||
# QToolTip wash while a normal-hint button does not.
|
||||
gated = panel._buttons[BeamlineStateEnum.BeamLocation]
|
||||
assert gated.cursor().shape() == Qt.CursorShape.ForbiddenCursor
|
||||
@@ -74,13 +74,13 @@ def test_availability_palette_and_cursors(qtbot):
|
||||
panel = _panel(qtbot)
|
||||
panel.set_current_state(BeamlineStateEnum.Maintenance)
|
||||
available = panel._buttons[BeamlineStateEnum.SampleExchange]
|
||||
grey = panel._buttons[BeamlineStateEnum.FluxMeasurement]
|
||||
gray = panel._buttons[BeamlineStateEnum.FluxMeasurement]
|
||||
assert STATE_AVAILABLE in available.styleSheet()
|
||||
assert available.cursor().shape() == Qt.CursorShape.PointingHandCursor
|
||||
assert not available.font().bold()
|
||||
assert STATE_UNAVAILABLE in grey.styleSheet()
|
||||
assert grey.cursor().shape() == Qt.CursorShape.ForbiddenCursor
|
||||
assert grey.toolTip() == ""
|
||||
assert STATE_UNAVAILABLE in gray.styleSheet()
|
||||
assert gray.cursor().shape() == Qt.CursorShape.ForbiddenCursor
|
||||
assert gray.toolTip() == ""
|
||||
assert available.toolTip() != ""
|
||||
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ def test_alt_wheel_axis_swap_still_changes_exposure(camera):
|
||||
|
||||
|
||||
def test_hover_hud_coords_and_scale_bar(camera):
|
||||
# Hover inside the image: bottom-right HUD paints coords + grey scale bar.
|
||||
# Hover inside the image: bottom-right HUD paints coords + gray scale bar.
|
||||
_mouse_move(camera, QPoint(400, 300))
|
||||
assert camera._hover_pos is not None
|
||||
camera.grab()
|
||||
|
||||
@@ -600,7 +600,7 @@ def test_nonstaff_beamline_gate_popups(qtbot, mock_ui_state):
|
||||
qtbot.mousePress(bar, Qt.MouseButton.LeftButton, pos=bar.tabRect(0).center())
|
||||
assert tip.showText.called, "gated tab click must explain the gate"
|
||||
|
||||
# The greyed-out Auxiliary-puck tab explains itself the same way.
|
||||
# The grayed-out Auxiliary-puck tab explains itself the same way.
|
||||
aux_bar = win.sample_lists_tabs.tabBar()
|
||||
with patch("aare.gui.main_window.QToolTip") as tip:
|
||||
qtbot.mousePress(aux_bar, Qt.MouseButton.LeftButton, pos=aux_bar.tabRect(1).center())
|
||||
|
||||
@@ -38,7 +38,7 @@ def test_stage_apply_settle(chi, qtbot):
|
||||
assert box.property("movestate") == "moving"
|
||||
assert not group.button.isEnabled()
|
||||
|
||||
group.update_actual("chi", 10.0) # still travelling
|
||||
group.update_actual("chi", 10.0) # still traveling
|
||||
assert box.property("movestate") == "moving"
|
||||
assert box.value == 25.0 # box keeps showing the target
|
||||
|
||||
|
||||
Reference in New Issue
Block a user