Add hostname and user to gui logs #91
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"label": "Python Active File",
|
||||
"adapter": "Debugpy",
|
||||
"program": "$ZED_FILE",
|
||||
"request": "launch",
|
||||
"justMyCode": false,
|
||||
},
|
||||
]
|
||||
@@ -368,7 +368,7 @@ class ImageStatsReceiver:
|
||||
self.print_thread_obj = threading.Thread(target=self.print_stats_thread, daemon=True)
|
||||
self.print_thread_obj.start()
|
||||
|
||||
print(f"Image stats receiver started - printing every 1 second")
|
||||
print("Image stats receiver started - printing every 1 second")
|
||||
|
||||
def stop(self):
|
||||
"""Stop the receiver and all threads"""
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from aarecommon.config.beamline import mx_beamline
|
||||
from aarecommon.math.diffraction_geometry import DiffractionGeometry
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
|
||||
from aare.daq.aaredb import AareWrapper
|
||||
from aare.daq.config import BeamlineConfig
|
||||
|
||||
@@ -8,7 +8,6 @@ from PySide6.QtWidgets import (
|
||||
QPushButton,
|
||||
QScrollArea,
|
||||
QStackedWidget,
|
||||
QSizePolicy,
|
||||
)
|
||||
from PySide6.QtCore import Qt, QPointF, QRectF
|
||||
from PySide6.QtGui import QPainter, QColor, QPen, QLinearGradient, QFont, QFontMetrics
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import datetime
|
||||
import functools
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from typing import List, Optional
|
||||
|
||||
import aareDB
|
||||
|
||||
@@ -16,8 +16,8 @@ from aarecommon.errors.exception_handler import (
|
||||
)
|
||||
from aarecommon.models.auth import BatonRequest, BatonRequestStatus, BatonStatus, BatonTransferQueue
|
||||
from aarecommon.models.models import SessionsStateEnum
|
||||
from fastapi import Depends, HTTPException, Request, status
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from fastapi import Depends, Request
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from pydantic import BaseModel
|
||||
|
||||
from aare.daq.config import BeamlineConfig
|
||||
@@ -148,7 +148,7 @@ def check_jwt_rw(cfg: BeamlineConfig, data: TokenData) -> None:
|
||||
|
||||
try:
|
||||
cfg.try_extend_active_session(data.session, SESSION_EXPIRE_SECONDS)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
# In case something is wrong but you are holder (maybe redis expiry?)
|
||||
cfg.try_set_active_session(data.session, SESSION_EXPIRE_SECONDS)
|
||||
|
||||
|
||||
+12
-15
@@ -7,8 +7,6 @@ from math import ceil
|
||||
from pathlib import Path
|
||||
from typing import Callable, List, Optional, Tuple
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from aarecommon.config.beamline import cfg_get
|
||||
from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.config.logger_events import (
|
||||
@@ -68,7 +66,6 @@ from aarecommon.models.raster_grid import CompletedRasterGrid, RasterGridRequest
|
||||
from aarecommon.models.rotation_scan import CompletedRotationScan, RotationScanRequest
|
||||
from aarecommon.models.tell import TellPhaseEnum, TellStateModel
|
||||
from aareDB import SampleEventType
|
||||
from jfjoch_client import ScanResult, ScanResultImagesInner
|
||||
|
||||
from aare.daq import workflows
|
||||
from aare.daq.aaredb import AareWrapper
|
||||
@@ -990,7 +987,7 @@ class AareDAQ:
|
||||
self.__aare.send_sample_event(
|
||||
sample_id=sample_id, event_type=event_type, comment=comment
|
||||
)
|
||||
except Exception as db_error:
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Failed to report operation error to database",
|
||||
extra={
|
||||
@@ -1291,7 +1288,7 @@ 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(f"initialise detector for raster")
|
||||
logger.info("initialise detector for raster")
|
||||
status = self.status
|
||||
self.__jfjoch.measure_raster(grid_request, status)
|
||||
logger.info("detector initialised")
|
||||
@@ -1607,7 +1604,7 @@ class AareDAQ:
|
||||
def state(self, target: BeamlineStateEnum):
|
||||
if target == BeamlineStateEnum.Moving:
|
||||
logger.error(
|
||||
f"Cannot explicitly move to busy state",
|
||||
"Cannot explicitly move to busy state",
|
||||
extra={"target": target, "state": self.__cfg.state},
|
||||
)
|
||||
raise Exception("Cannot explicitly move to busy state")
|
||||
@@ -1868,7 +1865,7 @@ class AareDAQ:
|
||||
self.__set_state(BeamlineStateEnum.RobotSampleExchange)
|
||||
except TransformationInvalidException as e:
|
||||
logger.error(f"Failed to go to robot sample exchange: {e}")
|
||||
logger.warning(f"trying to day and park without unmounting first")
|
||||
logger.warning("trying to day and park without unmounting first")
|
||||
try:
|
||||
self._execute_dry(park=park, unmount=unmount)
|
||||
self.__cfg.state_busy = False
|
||||
@@ -2102,7 +2099,7 @@ class AareDAQ:
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__cfg.state_busy = False
|
||||
return result
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__cfg.state_busy = False
|
||||
raise
|
||||
@@ -2270,7 +2267,7 @@ class AareDAQ:
|
||||
self.__devs.smargon_pos = sc
|
||||
self.__devs.smargon_wait()
|
||||
self.__cfg.state_busy = False
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.__cfg.state_busy = False
|
||||
raise
|
||||
pass
|
||||
@@ -2280,7 +2277,7 @@ class AareDAQ:
|
||||
try:
|
||||
self.__cfg.mark_beam(x_pxl, y_pxl, self.__devs.zoom)
|
||||
self.__cfg.state_busy = False
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.__cfg.state_busy = False
|
||||
raise
|
||||
|
||||
@@ -2411,7 +2408,7 @@ class AareDAQ:
|
||||
|
||||
self.__cfg.state_busy = False
|
||||
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.__cfg.zoom_mode = ZoomModeEnum.User
|
||||
self.__cfg.state_busy = False
|
||||
raise
|
||||
@@ -2617,7 +2614,7 @@ class AareDAQ:
|
||||
msg = f"Ended automation operation after {operation.value}"
|
||||
|
||||
if error:
|
||||
msg += f"with an error"
|
||||
msg += "with an error"
|
||||
logger.error(f"{msg}, time taken {time.perf_counter() - start} seconds.")
|
||||
try:
|
||||
if self.__cfg.state_busy:
|
||||
@@ -2634,7 +2631,7 @@ class AareDAQ:
|
||||
)
|
||||
|
||||
else:
|
||||
msg += f" successfully"
|
||||
msg += " successfully"
|
||||
logger.info(f"{msg}, time taken {time.perf_counter() - start} seconds.")
|
||||
self.__cfg.state_busy = False
|
||||
end = time.perf_counter()
|
||||
@@ -3329,7 +3326,7 @@ class AareDAQ:
|
||||
aerotech_connected = False
|
||||
smargon_connected = False
|
||||
zoom = self.__devs.zoom
|
||||
logger.warning(f"Safe geometry failed: falling back to default settings")
|
||||
logger.warning("Safe geometry failed: falling back to default settings")
|
||||
fallback = SampleGeometryModel(
|
||||
beam_location_pxl=self.__cfg.beam_mark_coeff.apply(zoom),
|
||||
pixel_in_mm=self.__cfg.pixel_to_mm(zoom),
|
||||
@@ -3534,7 +3531,7 @@ class AareDAQ:
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__cfg.state_busy = False
|
||||
return None
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
self.__set_state(BeamlineStateEnum.SampleAlignment)
|
||||
self.__cfg.state_busy = False
|
||||
raise
|
||||
|
||||
@@ -5,7 +5,6 @@ import time
|
||||
# - property to read device value
|
||||
# - setter with option to do sync/async move
|
||||
# - property setter, which assumes that sync move is done (excl. zoom, which is async by default)
|
||||
import numpy as np
|
||||
from aarecommon.config.beamline import cfg_get
|
||||
from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.config.logger_events import log_timing
|
||||
@@ -16,14 +15,13 @@ from epics import PV
|
||||
|
||||
from aare.devices import aerotech, smargon
|
||||
from aare.devices.area_detector import AutoEnum, epicsAD
|
||||
from aare.devices.bec_worker import BECClientWorker, DetectorCoverEnum
|
||||
from aare.devices.bec_worker import BECClientWorker
|
||||
from aare.devices.enum_pv import EnumPV
|
||||
from aare.devices.experimental_hutch_shutter import ExperimentalHutchShutter
|
||||
from aare.devices.my_motor import MyMotor
|
||||
from aare.devices.pss_state import PssState
|
||||
from aare.devices.set_get_pv import PredefinedPV, SetGetPV
|
||||
from aare.devices.tell_client import make_tell_client
|
||||
from aare.devices.zmq_client import ZMQCameraClient
|
||||
|
||||
logger = setup_logger("aareDAQ")
|
||||
|
||||
@@ -76,7 +74,7 @@ class BeamlineDevices:
|
||||
self.__ringcurrent = self.bec_worker.ring_current
|
||||
|
||||
self.__zoom = SetGetPV(
|
||||
name=f"zoom", setpv=f"{BEAMLINE}-ES-MS:ZOOM.VAL", getpv=f"{BEAMLINE}-ES-MS:ZOOM.RBV"
|
||||
name="zoom", setpv=f"{BEAMLINE}-ES-MS:ZOOM.VAL", getpv=f"{BEAMLINE}-ES-MS:ZOOM.RBV"
|
||||
)
|
||||
|
||||
self.__cryojet_pos = EnumPV(
|
||||
|
||||
@@ -187,7 +187,7 @@ class FaceDetectionService:
|
||||
self.ctx.deps.devs.aerotech_omega = flat_face_angle
|
||||
|
||||
samples_out = fd.get_samples_out(boxes)
|
||||
self.logger.info(f"Face detection sequence complete")
|
||||
self.logger.info("Face detection sequence complete")
|
||||
|
||||
payload = {
|
||||
"running": False,
|
||||
|
||||
@@ -2,7 +2,6 @@ import copy
|
||||
import time
|
||||
from math import ceil, floor
|
||||
|
||||
import cv2
|
||||
from aarecommon.config.beamline import cfg_get
|
||||
from aarecommon.config.logger_events import (
|
||||
geom_log_context,
|
||||
@@ -11,7 +10,7 @@ from aarecommon.config.logger_events import (
|
||||
raster_request_log_context,
|
||||
sample_log_context,
|
||||
)
|
||||
from aarecommon.errors.exception_handler import AutoRasterSampleSkipped, RasterScanException
|
||||
from aarecommon.errors.exception_handler import RasterScanException
|
||||
from aarecommon.math.coordinate import AerotechCoordinate, Coordinate, SmargonCoordinate
|
||||
from aarecommon.math.find_xtal import (
|
||||
compute_crystal_score_array,
|
||||
@@ -37,7 +36,7 @@ from aare.daq.operations.common.ml_bounding_box import (
|
||||
build_ml_raster_plan,
|
||||
get_ml_bounding_box,
|
||||
)
|
||||
from aare.daq.operations.raster.models import RasterBoundingBoxResult, RasterContext
|
||||
from aare.daq.operations.raster.models import RasterContext
|
||||
from aare.devices.area_detector import AutoEnum
|
||||
|
||||
|
||||
|
||||
+20
-21
@@ -9,7 +9,6 @@ from contextlib import asynccontextmanager
|
||||
from typing import AsyncGenerator, Optional
|
||||
|
||||
import cv2
|
||||
import urllib3
|
||||
import uvicorn
|
||||
from aarecommon.config.beamline import mx_beamline
|
||||
from aarecommon.config.logger import get_uvicorn_logging_config, setup_logger
|
||||
@@ -46,7 +45,7 @@ from aareDB import SampleEventType
|
||||
from fastapi import Depends, FastAPI, HTTPException, Request
|
||||
from fastapi import status as api_status
|
||||
from fastapi.concurrency import run_in_threadpool
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from starlette.responses import StreamingResponse
|
||||
|
||||
from aare.daq import auth
|
||||
@@ -89,35 +88,35 @@ async def lifespan(application: FastAPI):
|
||||
each worker gets its own fresh Redis, BEC, EPICS, and TELL connections.
|
||||
"""
|
||||
global bl, cfg, daq
|
||||
logger.warning(f"something!!!")
|
||||
logger.warning("something!!!")
|
||||
await asyncio.sleep(random.uniform(0.5, 3.0))
|
||||
|
||||
logger.info(f"Worker {os.getpid()} starting initialisation...")
|
||||
|
||||
# ── Core objects (Redis, EPICS PVs, BEC, TELL, JFJoch, etc.) ──
|
||||
bl = mx_beamline()
|
||||
logger.warning(f"something after bl!!!")
|
||||
logger.warning("something after bl!!!")
|
||||
cfg = BeamlineConfig(bl)
|
||||
logger.warning(f"something after cfg!!!")
|
||||
logger.warning("something after cfg!!!")
|
||||
daq = AareDAQ(cfg, bl)
|
||||
logger.warning(f"something after daq!!!")
|
||||
logger.warning("something after daq!!!")
|
||||
|
||||
try:
|
||||
cfg.reset_automation_progress()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to reset automation progress Redis keys: {e}")
|
||||
logger.warning(f"something after reset automation!!!")
|
||||
logger.warning("something after reset automation!!!")
|
||||
try:
|
||||
daq.refresh_detector_metadata_cache()
|
||||
except Exception as e:
|
||||
logger.warning(f"Initial hardware metadata refresh failed: {e}")
|
||||
logger.warning(f"something after refresh detector metadata!!!")
|
||||
logger.warning("something after refresh detector metadata!!!")
|
||||
# ── Initial TELL sync ──
|
||||
try:
|
||||
daq.sync_current_sample_from_tell(force=True)
|
||||
except Exception as e:
|
||||
logger.warning(f"Initial sample sync from TELL failed: {e}")
|
||||
logger.warning(f"something after sync current sample!!!")
|
||||
logger.warning("something after sync current sample!!!")
|
||||
# ── Wire callbacks ──
|
||||
daq.set_face_detection_progress_callback(_push_face_detection_progress)
|
||||
daq.set_automation_progress_callback(_push_automation_progress)
|
||||
@@ -546,7 +545,7 @@ async def save_abr_meas_pos(token: str = Depends(oauth2_scheme)):
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Save abr")
|
||||
logger.debug("Save abr")
|
||||
auth.check_jwt_staff(cfg, auth.parse_token(token))
|
||||
daq.save_abr_meas_pos()
|
||||
return "OK"
|
||||
@@ -841,7 +840,7 @@ async def goto_abr_meas_pos(token: str = Depends(oauth2_scheme)):
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Go to ABR meas pos")
|
||||
logger.debug("Go to ABR meas pos")
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.goto_abr_meas_pos()
|
||||
return "OK"
|
||||
@@ -877,7 +876,7 @@ async def clear_beam_mark(token: str = Depends(oauth2_scheme)):
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Clear beam mark")
|
||||
logger.debug("Clear beam mark")
|
||||
auth.check_jwt_staff(cfg, auth.parse_token(token))
|
||||
daq.clear_mark_beam()
|
||||
return "OK"
|
||||
@@ -968,7 +967,7 @@ async def samcam_autofocus(s: AutofocusSettings, token: str = Depends(oauth2_sch
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"SamCam AutoFocus")
|
||||
logger.debug("SamCam AutoFocus")
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.auto_focus(s)
|
||||
return "OK"
|
||||
@@ -1146,7 +1145,7 @@ async def unmount(token: str = Depends(oauth2_scheme)):
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Unmount")
|
||||
logger.debug("Unmount")
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.sample = None
|
||||
return "OK"
|
||||
@@ -1725,7 +1724,7 @@ async def cancel(token: str = Depends(oauth2_scheme)):
|
||||
Args:
|
||||
token: OAuth2 access token.
|
||||
"""
|
||||
logger.debug(f"Scan Cancel")
|
||||
logger.debug("Scan Cancel")
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.cancel()
|
||||
|
||||
@@ -1742,7 +1741,7 @@ async def alc_center_loop(token: str = Depends(oauth2_scheme)) -> str:
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"ALC")
|
||||
logger.debug("ALC")
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.auto_loop_center()
|
||||
return "OK"
|
||||
@@ -1992,7 +1991,7 @@ async def end_session(token: str = Depends(oauth2_scheme)) -> str:
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Try to end Session")
|
||||
logger.debug("Try to end Session")
|
||||
# End active session will only delete session, if it is equal to token value
|
||||
# so no need to check R/W permissions
|
||||
token_data = auth.parse_token(token)
|
||||
@@ -2012,7 +2011,7 @@ async def force_current_session(token: str = Depends(oauth2_scheme)) -> str:
|
||||
Returns:
|
||||
"OK" on success.
|
||||
"""
|
||||
logger.debug(f"Try to grab session")
|
||||
logger.debug("Try to grab session")
|
||||
data = auth.parse_token(token)
|
||||
# Counterintuitive, this operation requires only R/O permission
|
||||
# as this is actually acquiring R/W permissions
|
||||
@@ -2233,7 +2232,7 @@ async def get_settings(token: str = Depends(oauth2_scheme)) -> BeamlineSettingsM
|
||||
Returns:
|
||||
BeamlineSettingsModel.
|
||||
"""
|
||||
logger.debug(f"Get settings")
|
||||
logger.debug("Get settings")
|
||||
auth.check_jwt_staff(cfg, auth.parse_token(token))
|
||||
return cfg.settings
|
||||
|
||||
@@ -2263,7 +2262,7 @@ async def get_cryo_settings(token: str = Depends(oauth2_scheme)) -> CryojetSetti
|
||||
Returns:
|
||||
CryojetSettingsModel.
|
||||
"""
|
||||
logger.debug(f"Get Cryo Settings")
|
||||
logger.debug("Get Cryo Settings")
|
||||
auth.check_jwt_staff(cfg, auth.parse_token(token))
|
||||
return cfg.cryojet_settings
|
||||
|
||||
@@ -2293,7 +2292,7 @@ async def get_all_pgroups(token: str = Depends(oauth2_scheme)):
|
||||
Returns:
|
||||
List of pgroup strings.
|
||||
"""
|
||||
logger.debug(f"Get all pgroups")
|
||||
logger.debug("Get all pgroups")
|
||||
auth.check_jwt_staff(cfg, auth.parse_token(token))
|
||||
|
||||
base_path = "/sls/mx/data/"
|
||||
|
||||
@@ -33,7 +33,6 @@ from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.errors.codes import AareErrorCode, code_for_exception_class
|
||||
from aarecommon.errors.exception_handler import (
|
||||
AareAuthError,
|
||||
AareException,
|
||||
AareUserError,
|
||||
AuthenticationException,
|
||||
AutomationError,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import time
|
||||
from enum import Enum
|
||||
from typing import Any, List, Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from aarecommon.config.beamline import cfg_get, mx_beamline
|
||||
from aarecommon.config.logger import setup_logger
|
||||
@@ -9,7 +9,7 @@ from aarecommon.errors.exception_handler import BECCommunicationError
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
from bec_ipython_client import BECIPythonClient
|
||||
from bec_ipython_client.signals import OperationMode
|
||||
from bec_lib.procedures.helper import BackendProcedureHelper, FrontendProcedureHelper
|
||||
from bec_lib.procedures.helper import FrontendProcedureHelper
|
||||
from bec_lib.service_config import ServiceConfig
|
||||
|
||||
logger = setup_logger("aareDAQ")
|
||||
@@ -281,7 +281,7 @@ class BECClientWorker:
|
||||
|
||||
def current_state(self):
|
||||
if self.simulated:
|
||||
logger.debug(f"Simulating check_beamline_state")
|
||||
logger.debug("Simulating check_beamline_state")
|
||||
return BeamlineState.MAINTENANCE
|
||||
return self.planner.current_state()
|
||||
|
||||
@@ -428,7 +428,7 @@ class BECClientWorker:
|
||||
try:
|
||||
return self.dev.det_z.position
|
||||
except Exception as e:
|
||||
self._raise_bec_error(e, operation=f"get_det_z", tags=["det_z"])
|
||||
self._raise_bec_error(e, operation="get_det_z", tags=["det_z"])
|
||||
|
||||
def det_z(self, value: float, timeout: int | None = None):
|
||||
"""timeout is None or integer in s"""
|
||||
@@ -444,7 +444,7 @@ class BECClientWorker:
|
||||
try:
|
||||
return self.dev.det_y.position
|
||||
except Exception as e:
|
||||
self._raise_bec_error(e, operation=f"get_det_z", tags=["det_z"])
|
||||
self._raise_bec_error(e, operation="get_det_z", tags=["det_z"])
|
||||
|
||||
def det_y(self, value: float, timeout: int | None = None):
|
||||
"""timeout is None or integer in s"""
|
||||
@@ -465,7 +465,7 @@ class BECClientWorker:
|
||||
except Exception as e:
|
||||
self._raise_bec_error(
|
||||
e,
|
||||
operation=f"backlight brightness, could not get backlight brightness",
|
||||
operation="backlight brightness, could not get backlight brightness",
|
||||
tags=["backlight"],
|
||||
)
|
||||
raise
|
||||
@@ -499,7 +499,7 @@ class BECClientWorker:
|
||||
except Exception as e:
|
||||
self._raise_bec_error(
|
||||
e,
|
||||
operation=f"backlight toggle, could not change backlight on/off ",
|
||||
operation="backlight toggle, could not change backlight on/off ",
|
||||
tags=["backlight"],
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Mapping, Optional, Union, Callable
|
||||
|
||||
from epics import PV, poll
|
||||
from epics import PV
|
||||
from aare.devices.mx_lib import pv_wait
|
||||
|
||||
RawValue = Union[str, float, int]
|
||||
|
||||
@@ -99,7 +99,7 @@ class Smargon(object):
|
||||
|
||||
@property
|
||||
def mode(self) -> SmargonMode:
|
||||
mode = self.gonget(f"mode")
|
||||
mode = self.gonget("mode")
|
||||
return SmargonMode(mode)
|
||||
|
||||
@mode.setter
|
||||
|
||||
@@ -372,7 +372,7 @@ class TellClient:
|
||||
if wait:
|
||||
try:
|
||||
self.check_command_ok(timeout=timeout, msg="Unmount message: ")
|
||||
except MountingFailed as e:
|
||||
except MountingFailed:
|
||||
result = self.get_result(self._last_cmd_id)
|
||||
logger.error(
|
||||
f"Unmount failed with status '{result.get('status')}' and payload: {result}"
|
||||
|
||||
@@ -5,7 +5,6 @@ with fallback to area_detector if ZMQ is unavailable.
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
import cv2
|
||||
|
||||
@@ -6,7 +6,9 @@ from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.models.auth import get_user
|
||||
from aarecommon.models.models import TokenData
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
def auth(base_url: str | None, cert_path: str | None) -> str:
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import getpass
|
||||
import socket
|
||||
|
||||
|
||||
def _try_clean_hostname(raw_name: str) -> str:
|
||||
return raw_name.removesuffix(".psi.ch")
|
||||
|
||||
|
||||
CLEAN_HOSTNAME = _try_clean_hostname(socket.gethostname())
|
||||
LOGGER_NAME = f"AareGUI: {CLEAN_HOSTNAME} - {getpass.getuser()}"
|
||||
+3
-2
@@ -7,13 +7,14 @@ from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
from PySide6 import QtGui
|
||||
from PySide6.QtCore import QCommandLineOption, QCommandLineParser
|
||||
from PySide6.QtWidgets import QApplication, QMessageBox, QProgressBar, QSplashScreen
|
||||
from PySide6.QtWidgets import QApplication, QMessageBox
|
||||
|
||||
from aare.gui.auth import auth
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.main_window import MainWindow
|
||||
from aare.gui.widgets.splash_screen import LoadingSplashScreen
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -15,7 +15,7 @@ from aarecommon.models.models import (
|
||||
TokenData,
|
||||
)
|
||||
from PySide6.QtCore import QEvent, QSettings, Qt, QTimer, Signal, Slot
|
||||
from PySide6.QtGui import QAction, QActionGroup, QGuiApplication, QKeySequence, QPixmap
|
||||
from PySide6.QtGui import QAction, QActionGroup, QGuiApplication, QKeySequence
|
||||
from PySide6.QtWidgets import (
|
||||
QDockWidget,
|
||||
QHBoxLayout,
|
||||
@@ -27,6 +27,8 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
# Gui Models
|
||||
from aare.gui.models.gui_state_manager import UIStateManager
|
||||
from aare.gui.panels.automation_panel import AutomationProgressWidget
|
||||
@@ -84,7 +86,7 @@ from aare.gui.widgets.no_wheel_scroll_area import NoWheelScrollArea
|
||||
from aare.gui.widgets.status_bar import StatusBar
|
||||
from aare.gui.widgets.video_image import VideoGraphicsView
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
@@ -9,7 +9,9 @@ from aarecommon.models.automation import AutomationProgress, StepStatus, Workflo
|
||||
from PySide6.QtCore import QTimer, Slot
|
||||
from PySide6.QtWidgets import QLabel, QVBoxLayout, QWidget
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class AutomationProgressWidget(QWidget):
|
||||
|
||||
@@ -5,10 +5,11 @@ from matplotlib.figure import Figure
|
||||
from PySide6.QtCore import Signal
|
||||
from PySide6.QtWidgets import QGridLayout, QLabel, QPushButton, QVBoxLayout, QWidget
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.widgets.number_line_edit import NumberLineEdit
|
||||
from aare.gui.widgets.title_label import TitleLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class FaceDetectionPanel(QWidget):
|
||||
|
||||
@@ -6,7 +6,9 @@ from PySide6.QtCore import QEvent, QPointF, Qt, Slot
|
||||
from PySide6.QtGui import QColor, QPainter, QPen
|
||||
from PySide6.QtWidgets import QGraphicsSimpleTextItem, QGridLayout, QLabel, QWidget
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class FluorescencePanel(QWidget):
|
||||
|
||||
@@ -25,14 +25,14 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.panels.beamline_recovery_panel import RecoveryPanel
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
from aare.gui.widgets.local_contact_status_widget import LocalContactStatusWidget
|
||||
from aare.gui.widgets.number_line_edit import NumberLineEdit
|
||||
from aare.gui.widgets.text_list_dialog import TextListDialog
|
||||
from aare.gui.widgets.title_label import TitleLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class LocalContactPanel(QFrame):
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.models.automation import AutomationProgress, StepStatus, WorkflowStateKind
|
||||
from PySide6.QtCore import QPointF, QRectF, Qt, QTimer, Signal, Slot
|
||||
from PySide6.QtGui import QColor, QFont, QFontMetrics, QLinearGradient, QPainter, QPen
|
||||
from PySide6.QtGui import QColor, QFont, QFontMetrics, QPainter, QPen
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
@@ -19,7 +17,9 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Colour palette (kept identical to gui_designer.py)
|
||||
@@ -290,19 +290,19 @@ class PortraitModePanel(QWidget):
|
||||
# ── Portrait alert toast (hidden by default) ───────────────────────
|
||||
self._alert_toast = QFrame()
|
||||
self._alert_toast.setVisible(False)
|
||||
self._alert_toast.setStyleSheet(f"""
|
||||
QFrame {{
|
||||
self._alert_toast.setStyleSheet("""
|
||||
QFrame {
|
||||
background: #1A0E0E;
|
||||
border: 1px solid #8f1d2c;
|
||||
border-radius: 10px;
|
||||
}}
|
||||
}
|
||||
""")
|
||||
toast_layout = QHBoxLayout(self._alert_toast)
|
||||
toast_layout.setContentsMargins(12, 8, 12, 8)
|
||||
self._alert_toast_label = QLabel("")
|
||||
self._alert_toast_label.setWordWrap(True)
|
||||
self._alert_toast_label.setStyleSheet(
|
||||
f"color: #ffb3bc; font-size: 11px; font-weight: 600; background: transparent;"
|
||||
"color: #ffb3bc; font-size: 11px; font-weight: 600; background: transparent;"
|
||||
)
|
||||
toast_layout.addWidget(self._alert_toast_label)
|
||||
# Dismiss button
|
||||
|
||||
@@ -40,7 +40,9 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -12,12 +12,13 @@ from PySide6.QtWidgets import (
|
||||
QSpacerItem,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.panels.scan_settings_panel import ScanSettingsPanel
|
||||
from aare.gui.scan_logic.raster_grid_manager import RasterGridManager, RasterGridMetric
|
||||
from aare.gui.widgets.number_line_edit import DbOverrideLineEdit
|
||||
from aare.gui.widgets.raster_grid_table import RasterGridTable
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
# TODO prevent raster if no grid, or at least rpevent smargon from doing danngerous move to 0,0,0!!!
|
||||
|
||||
@@ -16,9 +16,10 @@ from PySide6.QtWidgets import (
|
||||
QTableView,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.widgets.title_label import TitleLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
def get_entry(sample: SampleShortInfo, column: int):
|
||||
|
||||
@@ -7,10 +7,11 @@ from aarecommon.models.rotation_scan import RotationScanRequest
|
||||
from PySide6.QtCore import Qt, Signal, Slot
|
||||
from PySide6.QtWidgets import QComboBox, QLabel, QMessageBox, QPushButton
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.panels.scan_settings_panel import ScanSettingsPanel
|
||||
from aare.gui.widgets.number_line_edit import CheckedLineEdit, DbOverrideLineEdit, NumberLineEdit
|
||||
from aare.gui.widgets.number_line_edit import DbOverrideLineEdit, NumberLineEdit
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
def add_screening_to_path(path):
|
||||
|
||||
@@ -20,11 +20,12 @@ from PySide6.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.models.sample_queue_model import SampleQueueSpreadsheet
|
||||
from aare.gui.widgets.message_box import LOW_CURRENT_THRESHOLD, conditions_auto_check
|
||||
from aare.gui.widgets.title_label import TitleLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class SampleQueuePanel(QFrame):
|
||||
|
||||
@@ -13,10 +13,11 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.widgets.message_box import precondition_check
|
||||
from aare.gui.widgets.number_line_edit import DbOverrideLineEdit
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class ScanSettingsPanel(QWidget):
|
||||
|
||||
@@ -6,10 +6,11 @@ from aarecommon.models.rotation_scan import RotationScanRequest
|
||||
from PySide6.QtCore import Qt, Signal, Slot
|
||||
from PySide6.QtWidgets import QGridLayout, QLabel, QPushButton, QSizePolicy, QSpacerItem, QWidget
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.panels.rotation_data_collection import add_data_to_path
|
||||
from aare.gui.widgets.number_line_edit import NumberLineEdit
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class SimpleRotationSettingsPanel(QWidget):
|
||||
@@ -107,13 +108,13 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("%", parent=self), 7, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Detector distance", parent=self), 8, 0)
|
||||
self.dtz_label = QLabel(f"--", parent=self)
|
||||
self.dtz_label = QLabel("--", parent=self)
|
||||
self.dtz_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.dtz_label, 8, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("mm", parent=self), 8, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Target Dose", parent=self), 9, 0)
|
||||
self.target_dose_label = QLabel(f"--", parent=self)
|
||||
self.target_dose_label = QLabel("--", parent=self)
|
||||
self.target_dose_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -121,7 +122,7 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("MGy", parent=self), 9, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Calculated Dose Rate", parent=self), 10, 0)
|
||||
self.calculated_dose_rate_label = QLabel(f"--", parent=self)
|
||||
self.calculated_dose_rate_label = QLabel("--", parent=self)
|
||||
self.calculated_dose_rate_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -129,7 +130,7 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("MGy s<sup>-1</sup>", parent=self), 10, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Wilson B Factor", parent=self), 11, 0)
|
||||
self.wilson_b_label = QLabel(f"--", parent=self)
|
||||
self.wilson_b_label = QLabel("--", parent=self)
|
||||
self.wilson_b_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -137,25 +138,25 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("Å<sup>2</sup>", parent=self), 11, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size x", parent=self), 12, 0)
|
||||
self.xtal_x_label = QLabel(f"--", parent=self)
|
||||
self.xtal_x_label = QLabel("--", parent=self)
|
||||
self.xtal_x_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_x_label, 12, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 12, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size y", parent=self), 13, 0)
|
||||
self.xtal_y_label = QLabel(f"--", parent=self)
|
||||
self.xtal_y_label = QLabel("--", parent=self)
|
||||
self.xtal_y_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_y_label, 13, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 13, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Crystal Size z", parent=self), 14, 0)
|
||||
self.xtal_z_label = QLabel(f"--", parent=self)
|
||||
self.xtal_z_label = QLabel("--", parent=self)
|
||||
self.xtal_z_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.xtal_z_label, 14, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("um", parent=self), 14, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Calculated Dose (xtal size)", parent=self), 15, 0)
|
||||
self.xtal_size_dose_label = QLabel(f"--", parent=self)
|
||||
self.xtal_size_dose_label = QLabel("--", parent=self)
|
||||
self.xtal_size_dose_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -171,13 +172,13 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("Å", parent=self), 16, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Flux", parent=self), 17, 0)
|
||||
self.flux_label = QLabel(f"--", parent=self)
|
||||
self.flux_label = QLabel("--", parent=self)
|
||||
self.flux_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
self._layout.addWidget(self.flux_label, 17, 1, 1, 3)
|
||||
self._layout.addWidget(QLabel("x 10<sup>9</sup> ph s<sup>-1</sup>", parent=self), 17, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Beam Size", parent=self), 18, 0)
|
||||
self.beam_size_label = QLabel(f"--", parent=self)
|
||||
self.beam_size_label = QLabel("--", parent=self)
|
||||
self.beam_size_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -185,7 +186,7 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self._layout.addWidget(QLabel("um<sup>2</sup>", parent=self), 18, 4)
|
||||
|
||||
self._layout.addWidget(QLabel("Calculated Dose", parent=self), 19, 0)
|
||||
self.calculated_dose_label = QLabel(f"--", parent=self)
|
||||
self.calculated_dose_label = QLabel("--", parent=self)
|
||||
self.calculated_dose_label.setAlignment(
|
||||
Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
|
||||
)
|
||||
@@ -355,7 +356,7 @@ class SimpleRotationSettingsPanel(QWidget):
|
||||
self.image_time_label.setText(f"{self.image_time_s:.4f}")
|
||||
|
||||
if self.dtz <= 0.0:
|
||||
self.dtz_label.setText(f"""<span style="color: red ; ">-</span>""")
|
||||
self.dtz_label.setText("""<span style="color: red ; ">-</span>""")
|
||||
elif self.dtz < self.__d.bl.dtz_min:
|
||||
self.dtz_label.setText(f"""<span style="color: red ; ">{self.dtz:.2f}</span>""")
|
||||
self.dtz = self.__d.bl.dtz_min
|
||||
|
||||
@@ -22,7 +22,9 @@ from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
)
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class InteractiveChartView(QChartView):
|
||||
|
||||
@@ -17,10 +17,11 @@ from PySide6.QtWidgets import (
|
||||
QTableView,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.models.user_sample_model import UserSampleSpreadsheet
|
||||
from aare.gui.widgets.title_label import TitleLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class TellSamplePanel(QFrame):
|
||||
|
||||
@@ -17,7 +17,9 @@ from aarecommon.models.raster_grid import (
|
||||
from PySide6.QtCore import QLineF, QObject, QPointF, QRect, QRectF, Qt, Signal, Slot
|
||||
from PySide6.QtGui import QBrush, QColor, QImage, QPainter, QPen
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class RasterGridMetric(Enum):
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import cv2
|
||||
import requests
|
||||
import numpy as np
|
||||
from PySide6.QtCore import QThread, Signal, QRect, QPoint
|
||||
from PySide6.QtGui import QImage, QPainter, QPen, QColor, Qt, QFontMetrics, QFont
|
||||
from io import BytesIO
|
||||
from PySide6.QtCore import QThread, Signal
|
||||
from PySide6.QtGui import QImage
|
||||
|
||||
|
||||
class VideoThread(QThread):
|
||||
|
||||
@@ -50,7 +50,9 @@ from jfjoch_client import ScanResult, ScanResultImagesInner
|
||||
from PySide6.QtCore import QByteArray, QObject, QTimer, QUrl, Signal, Slot
|
||||
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest, QSslError
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
SPREADHSEET_FREQUENCY = 25 # Every 5 seconds
|
||||
|
||||
@@ -796,11 +798,11 @@ class DAQWorker(QObject):
|
||||
|
||||
@Slot()
|
||||
def close_shutter(self):
|
||||
self.generic_post(f"beamline/shutter?val=false")
|
||||
self.generic_post("beamline/shutter?val=false")
|
||||
|
||||
@Slot()
|
||||
def open_shutter(self):
|
||||
self.generic_post(f"beamline/shutter?val=true")
|
||||
self.generic_post("beamline/shutter?val=true")
|
||||
|
||||
@Slot()
|
||||
def center_loop(self):
|
||||
@@ -1152,7 +1154,7 @@ class DAQWorker(QObject):
|
||||
@Slot()
|
||||
def load_spreadsheet(self):
|
||||
if self.__base_url is None:
|
||||
logger.info(f"GET /sample/spreadsheet")
|
||||
logger.info("GET /sample/spreadsheet")
|
||||
return
|
||||
|
||||
request = QNetworkRequest(QUrl(f"{self.__base_url}/sample/spreadsheet"))
|
||||
@@ -1163,7 +1165,7 @@ class DAQWorker(QObject):
|
||||
@Slot()
|
||||
def load_reference_tools(self):
|
||||
if self.__base_url is None:
|
||||
logger.info(f"GET /sample/reference_tools")
|
||||
logger.info("GET /sample/reference_tools")
|
||||
return
|
||||
request = QNetworkRequest(QUrl(f"{self.__base_url}/sample/reference_tools"))
|
||||
request.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8"))
|
||||
@@ -1395,7 +1397,7 @@ class DAQWorker(QObject):
|
||||
|
||||
@Slot()
|
||||
def beam_mark_clear(self):
|
||||
self.generic_post(f"beam_mark/clear")
|
||||
self.generic_post("beam_mark/clear")
|
||||
|
||||
@Slot(float, float)
|
||||
def beam_center(self, x: float, y: float):
|
||||
@@ -1729,7 +1731,7 @@ class DAQWorker(QObject):
|
||||
|
||||
@Slot(SampleShortInfo)
|
||||
def sample_manual(self, s: SampleShortInfo):
|
||||
self.generic_post(f"sample/manual", s.model_dump_json())
|
||||
self.generic_post("sample/manual", s.model_dump_json())
|
||||
|
||||
@Slot()
|
||||
def cancel(self):
|
||||
@@ -1751,7 +1753,7 @@ class DAQWorker(QObject):
|
||||
Request an ML-based bounding box for the current sample.
|
||||
"""
|
||||
if self.__base_url is None:
|
||||
logger.info(f"POST /alc/ml_bounding_box")
|
||||
logger.info("POST /alc/ml_bounding_box")
|
||||
return
|
||||
|
||||
request = QNetworkRequest(QUrl(f"{self.__base_url}/alc/ml_bounding_box"))
|
||||
@@ -2200,7 +2202,7 @@ class DAQWorker(QObject):
|
||||
|
||||
if int(status) == 404 and url.endswith("/meta/error-codes"):
|
||||
reply.deleteLater()
|
||||
logger.error(f"Error codes not found on server.")
|
||||
logger.error("Error codes not found on server.")
|
||||
return
|
||||
|
||||
payload = self.handle_response(reply)
|
||||
|
||||
@@ -10,7 +10,9 @@ from aarecommon.models.models import DAQStatusModel
|
||||
from PySide6.QtCore import QThread, Signal, Slot
|
||||
from PySide6.QtGui import QImage, QPixmap
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class PredictionSubscriber(QThread):
|
||||
|
||||
@@ -7,7 +7,6 @@ from typing import Any
|
||||
from PySide6.QtCore import (
|
||||
QEasingCurve,
|
||||
QObject,
|
||||
QPoint,
|
||||
QPropertyAnimation,
|
||||
Property,
|
||||
QRect,
|
||||
|
||||
@@ -14,7 +14,6 @@ from aare.gui.tutorials.tutorial_models import (
|
||||
TutorialContext,
|
||||
TutorialEvent,
|
||||
TutorialScenario,
|
||||
TutorialStepDefinition,
|
||||
TutorialTarget,
|
||||
TutorialTextRef,
|
||||
)
|
||||
|
||||
@@ -3,7 +3,9 @@ from PySide6.QtCore import Qt, QTimer, Slot
|
||||
from PySide6.QtGui import QColor
|
||||
from PySide6.QtWidgets import QFrame, QGraphicsDropShadowEffect, QHBoxLayout, QLabel, QSizePolicy
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class AlertBanner(QFrame):
|
||||
|
||||
@@ -37,11 +37,12 @@ from PySide6.QtWidgets import (
|
||||
QToolTip,
|
||||
)
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.models.bookmark import SmargonBookmarkList
|
||||
from aare.gui.scan_logic.raster_grid_manager import RasterGridManager
|
||||
from aare.gui.widgets.busy_overlay import BusyOverlayStyle, build_busy_overlay_style
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class SampleCameraImageState(Enum):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import jwt
|
||||
from aarecommon.models.auth import get_user
|
||||
|
||||
@@ -4,7 +4,9 @@ from aarecommon.config.logger import setup_logger
|
||||
from PySide6.QtCore import QEventLoop, QTimer
|
||||
from PySide6.QtWidgets import QCheckBox, QMessageBox
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
LOW_CURRENT_THRESHOLD = 100.0
|
||||
SNOOZE_SECONDS = 3600.0 # "Don't ask again for 1 hour"
|
||||
@@ -150,7 +152,7 @@ def experiment_hutch_shutter_check(parent, shutter_state) -> bool:
|
||||
return True
|
||||
else:
|
||||
reply = reply_box(
|
||||
parent, title="Experiment shutter open", msg=f"Experiment shutter is Closed."
|
||||
parent, title="Experiment shutter open", msg="Experiment shutter is Closed."
|
||||
)
|
||||
return reply == QMessageBox.StandardButton.Yes
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import math
|
||||
|
||||
from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.models.auth import BatonRequestStatus, BatonStatus
|
||||
from aarecommon.models.auth import BatonStatus
|
||||
from aarecommon.models.models import BeamlineStateEnum, DAQStatusModel, SessionsStateEnum, TokenData
|
||||
from PySide6.QtCore import QPoint, QTimer, Signal, Slot
|
||||
from PySide6.QtGui import QFont
|
||||
from PySide6.QtWidgets import QDialog, QLabel, QMenu, QMessageBox, QSizePolicy, QStatusBar
|
||||
|
||||
from aare.gui.constants import LOGGER_NAME
|
||||
from aare.gui.widgets.baton_request_dialog import BatonRequestDialog
|
||||
from aare.gui.widgets.clickable_label import ClickableLabel
|
||||
from aare.gui.widgets.pgroup_dialog import PGroupDialog
|
||||
from aare.gui.widgets.value_label import ValueLabel
|
||||
|
||||
logger = setup_logger("aareGUI")
|
||||
logger = setup_logger(LOGGER_NAME)
|
||||
|
||||
|
||||
class StatusBar(QStatusBar):
|
||||
@@ -135,12 +136,12 @@ class StatusBar(QStatusBar):
|
||||
try:
|
||||
self.__status = status
|
||||
if status.bl.flux_ph_s is None:
|
||||
self.flux.set_value(f"0")
|
||||
self.flux.set_value("0")
|
||||
else:
|
||||
self.flux.set_value(f"{(status.bl.flux_ph_s / 1e9):.0f}")
|
||||
|
||||
if status.bl.transmission is None:
|
||||
self.transmission.set_value(f"(moving)")
|
||||
self.transmission.set_value("(moving)")
|
||||
else:
|
||||
self.transmission.set_value(f"{status.bl.transmission:.5f}")
|
||||
|
||||
@@ -163,11 +164,11 @@ class StatusBar(QStatusBar):
|
||||
|
||||
if status.bl.shutter_open:
|
||||
self.shutter_label.setText(
|
||||
f"""Fast Shutter: <span style="color: red ; "> Open ☢️ </span>"""
|
||||
"""Fast Shutter: <span style="color: red ; "> Open ☢️ </span>"""
|
||||
)
|
||||
else:
|
||||
self.shutter_label.setText(
|
||||
f"""Fast Shutter: <span style="color: green ; "> Closed 🚪 </span>"""
|
||||
"""Fast Shutter: <span style="color: green ; "> Closed 🚪 </span>"""
|
||||
)
|
||||
|
||||
if status.bl.exp_shutter_open:
|
||||
@@ -182,7 +183,7 @@ class StatusBar(QStatusBar):
|
||||
if status.session.current_pgroup is not None:
|
||||
self.pgroup_label.setText(f"""p-group: {status.session.current_pgroup} """)
|
||||
else:
|
||||
self.pgroup_label.setText(f"Inactive p-group ")
|
||||
self.pgroup_label.setText("Inactive p-group ")
|
||||
|
||||
self.state_label.setText(f"""State: {status.state.display_name()} """)
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ These cover:
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from aarecommon.errors.exception_handler import (
|
||||
AareAuthError,
|
||||
AareDBCommunicationError,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
from aarecommon.models.aerotech import (
|
||||
AerotechAxisStatus,
|
||||
AerotechRotationScanRequest,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
from aarecommon.math.autofocus import focus_measure_blob_size, focus_measure_edges
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
from aarecommon.models.models import (
|
||||
BeamlineStateEnum,
|
||||
BeamMarkCoeffModel,
|
||||
|
||||
@@ -2,7 +2,6 @@ import logging
|
||||
import types
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from aarecommon.math.coordinate import Coordinate, SmargonCoordinate
|
||||
from aarecommon.math.sample_geometry import SampleGeometryModel
|
||||
from aarecommon.models.models import MLBoxType, MLOutputModel
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import time
|
||||
import uuid
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import jwt
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
# Mock environment variable before importing auth
|
||||
with patch.dict("os.environ", {"JWT_AAREDAQ_KEY": "test_secret"}):
|
||||
@@ -15,7 +12,6 @@ with patch.dict("os.environ", {"JWT_AAREDAQ_KEY": "test_secret"}):
|
||||
cancel_baton_request,
|
||||
check_jwt_ro,
|
||||
check_jwt_rw,
|
||||
check_jwt_staff,
|
||||
check_jwt_staff_only,
|
||||
create_access_token,
|
||||
force_current_sesion,
|
||||
@@ -32,7 +28,6 @@ from aarecommon.models.auth import (
|
||||
BatonRequest,
|
||||
BatonRequestStatus,
|
||||
BatonStatus,
|
||||
BatonTransferQueue,
|
||||
)
|
||||
from aarecommon.models.models import SessionsStateEnum
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
import cv2
|
||||
from aare.daq.beamcenterfit import beamcenter_fit, Gaussian2Dfit
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ from aareDB import SampleEventType
|
||||
from aare.daq.config import ABR_POS_MOUNT, BeamlineStateEnum
|
||||
from aare.daq.daq import AareDAQ
|
||||
from aare.daq.operations.mounting.models import MountingContext, MountingResult
|
||||
from aare.daq.operations.mounting.service import MountingService
|
||||
from aare.daq.operations.screenshot.service import ScreenshotService
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import types
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import patch
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
@@ -13,11 +13,10 @@ import json
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from aarecommon.errors.codes import AareErrorCode, AuthErrorCode
|
||||
from aarecommon.errors.codes import AuthErrorCode
|
||||
from aarecommon.errors.exception_handler import (
|
||||
AareAuthError,
|
||||
AareDBCommunicationError,
|
||||
AareException,
|
||||
AareUserError,
|
||||
AuthenticationException,
|
||||
AutomationError,
|
||||
@@ -262,13 +261,10 @@ def test_only_four_root_handlers_plus_fallbacks(app):
|
||||
"""
|
||||
from aarecommon.errors.exception_handler import (
|
||||
AareDBCommunicationError,
|
||||
CriticalTellException,
|
||||
LoopCenteringFailed,
|
||||
MountingFailed,
|
||||
SmargonCommunicationError,
|
||||
TellCommunicationError,
|
||||
UnmountingFailed,
|
||||
WarningTellException,
|
||||
)
|
||||
|
||||
registered = set(app.exception_handlers.keys())
|
||||
|
||||
@@ -3,7 +3,6 @@ from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from aarecommon.models.models import SampleShortInfoList
|
||||
|
||||
from aare.daq.spreadsheetupdater import get_ws_headers, on_message, set_spreadsheet_in_redis
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
import json
|
||||
from unittest.mock import MagicMock, patch
|
||||
from aare.daq import tellupdater
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from aarecommon.models.models import StagePositionEnum
|
||||
|
||||
from aare.daq.config import ABR_OMEGA_MOUNT, ABR_POS_MOUNT
|
||||
from aare.daq.workflows import (
|
||||
|
||||
@@ -5,7 +5,7 @@ from aarecommon.errors.exception_handler import AerotechCommunicationError
|
||||
from aarecommon.math.coordinate import AerotechCoordinate, Coordinate
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
|
||||
from aare.devices.aerotech import AEROTECH_HOME, AerotechController
|
||||
from aare.devices.aerotech import AerotechController
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import patch
|
||||
from enum import Enum
|
||||
from aare.devices.enum_pv import EnumPV
|
||||
from aare.devices.set_get_pv import MoveResult
|
||||
|
||||
|
||||
class MockPV:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
|
||||
from aare.devices.experimental_hutch_shutter import ExperimentalHutchShutter
|
||||
|
||||
@@ -8,7 +8,7 @@ from aare.devices.fluorimeter import Fluorimeter
|
||||
|
||||
@patch("aare.devices.fluorimeter.PV")
|
||||
def test_fluorimeter_init(mock_pv):
|
||||
fluo = Fluorimeter(MXBeamline.X06DA)
|
||||
_ = Fluorimeter(MXBeamline.X06DA)
|
||||
# Lots of PVs in __init__
|
||||
assert mock_pv.call_count >= 20
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch, PropertyMock
|
||||
|
||||
from aare.devices.my_motor import MyMotor
|
||||
|
||||
|
||||
@@ -27,7 +29,7 @@ def mock_motor_base():
|
||||
|
||||
def test_my_motor_init(mock_motor_base):
|
||||
mock_init, _, _, _ = mock_motor_base
|
||||
m = MyMotor("X10SA-DI-MTR-01")
|
||||
_ = MyMotor("X10SA-DI-MTR-01")
|
||||
mock_init.assert_called_with("X10SA-DI-MTR-01", timeout=5.0)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from aare.devices.workflow_tools import wait_position
|
||||
import time
|
||||
|
||||
|
||||
class MockMotor:
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import sys
|
||||
import types
|
||||
|
||||
from aarecommon.models.automation import StepStatus, WorkflowStateKind
|
||||
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
|
||||
jfjoch_client_module = types.ModuleType("jfjoch_client")
|
||||
jfjoch_client_module.ScanResult = object
|
||||
jfjoch_client_module.ScanResultImagesInner = object
|
||||
@@ -13,10 +17,6 @@ sys.modules.setdefault("jfjoch_client", jfjoch_client_module)
|
||||
sys.modules.setdefault("jfjoch_client.models", jfjoch_client_models_module)
|
||||
sys.modules.setdefault("jfjoch_client.models.scan_result", jfjoch_client_scan_result_module)
|
||||
|
||||
from aarecommon.models.automation import StepStatus, WorkflowStateKind
|
||||
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
|
||||
|
||||
def test_parse_automation_progress_from_sse_payload():
|
||||
progress_payload = {
|
||||
|
||||
@@ -5,8 +5,6 @@ import cv2
|
||||
import numpy as np
|
||||
import pytest
|
||||
import zmq
|
||||
from aarecommon.models.models import DAQStatusModel
|
||||
from PySide6.QtGui import QPixmap
|
||||
|
||||
from aare.gui.threads.camera_thread import SampleCameraThread
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import sys
|
||||
import types
|
||||
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
|
||||
jfjoch_client_module = types.ModuleType("jfjoch_client")
|
||||
jfjoch_client_module.ScanResult = object
|
||||
jfjoch_client_module.ScanResultImagesInner = object
|
||||
@@ -13,8 +15,6 @@ sys.modules.setdefault("jfjoch_client", jfjoch_client_module)
|
||||
sys.modules.setdefault("jfjoch_client.models", jfjoch_client_models_module)
|
||||
sys.modules.setdefault("jfjoch_client.models.scan_result", jfjoch_client_scan_result_module)
|
||||
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
|
||||
|
||||
def test_is_critical_uses_body_flag_when_present():
|
||||
assert DAQWorker._is_critical({"critical": False}) is False
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from aare.gui.main_window import MainWindow
|
||||
|
||||
@@ -84,7 +83,7 @@ def test_main_window_mount_view(qtbot, mock_ui_state):
|
||||
def test_mark_user_interaction_reports_backend(qtbot, mock_ui_state):
|
||||
with (
|
||||
patch("requests.get"),
|
||||
patch("aare.gui.main_window.DAQWorker") as mock_daq_cls,
|
||||
patch("aare.gui.main_window.DAQWorker"),
|
||||
patch("aare.gui.main_window.PredictionSubscriber"),
|
||||
patch("aare.gui.main_window.VideoThread"),
|
||||
patch("aare.gui.main_window.JFJochDBusClient"),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
from PySide6.QtWidgets import QMessageBox
|
||||
from aare.gui.widgets.message_box import (
|
||||
|
||||
@@ -2,7 +2,6 @@ import pytest
|
||||
from aarecommon.math.coordinate import Coordinate, SmargonCoordinate
|
||||
from aarecommon.math.diffraction_geometry import DiffractionGeometry
|
||||
from aarecommon.math.sample_geometry import SampleGeometryModel
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
from aarecommon.models.models import (
|
||||
BeamlineStateEnum,
|
||||
BeamlineStatus,
|
||||
@@ -10,7 +9,6 @@ from aarecommon.models.models import (
|
||||
SampleCameraSettings,
|
||||
SessionStatus,
|
||||
)
|
||||
from PySide6.QtCore import Qt
|
||||
|
||||
from aare.gui.panels.status_panel import StatusPanel
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import pytest
|
||||
from PySide6.QtCore import QByteArray, QUrl
|
||||
from PySide6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
|
||||
from PySide6.QtCore import QByteArray
|
||||
from PySide6.QtNetwork import QNetworkReply
|
||||
from aare.gui.threads.sse_client import SSEClient
|
||||
from unittest.mock import MagicMock, patch
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from aarecommon.models.models import DAQStatusModel, DewarAddress, SampleShortInfo
|
||||
|
||||
from aare.gui.scan_logic.sample_mount_logic import SampleMountLogic
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
from PySide6.QtWidgets import QWidget
|
||||
from aare.gui.tutorials.tutorial_manager import TutorialManager
|
||||
from aare.gui.tutorials.tutorial_models import (
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import pytest
|
||||
from PySide6.QtCore import Qt
|
||||
from aare.gui.widgets.alert_banner import AlertBanner
|
||||
from aare.gui.widgets.status_label import StatusLabel
|
||||
|
||||
|
||||
Reference in New Issue
Block a user