diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4404bc4f..813f7ad3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: defaults: run: shell: bash -l {0} - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: max-parallel: 5 steps: @@ -29,8 +29,6 @@ jobs: uses: mamba-org/setup-micromamba@v1 with: environment-file: environment.yml - - name: Setup X virtual frame buffer - run: Xvfb $DISPLAY & - name: Install haven run: pip install -e . - name: Environment info @@ -38,11 +36,15 @@ jobs: env micromamba info micromamba list - - name: Lint with flake8 + - name: Lint run: | - # stop the build if there are Python syntax errors or undefined names + # Check for syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # Make sure black code formatting is applied + black --check --preview src/ + # Make sure import orders are correct + isort --check src/ # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest - run: pytest --timeout=120 + - name: Test with pytest in Xvfb + run: xvfb-run python -m pytest -vv --timeout=120 diff --git a/environment.yml b/environment.yml index f2441cfc..4896ec6b 100644 --- a/environment.yml +++ b/environment.yml @@ -34,7 +34,7 @@ dependencies: - numba>=0.56 # Ensures 0.53 (broken) isn't installed # --- testing and quality assurance - - black + - black >=22.1 - flake8 - pre-commit - pylint @@ -90,6 +90,7 @@ dependencies: - ophyd >=1.6.3 - pcdsdevices # For extra signal types - pydm >=1.18.0 + - typhos - p4p - tiled-server - tiled-client >= 0.1.0a106 # 2023-10-02 to get new Cache() behavior diff --git a/ipython_startup.py b/ipython_startup.py index 1781e178..71bd9936 100644 --- a/ipython_startup.py +++ b/ipython_startup.py @@ -1,10 +1,10 @@ -from bluesky import plans as bp, plan_stubs as bps, RunEngine, suspenders -from bluesky.simulators import summarize_plan -from bluesky.callbacks.best_effort import BestEffortCallback -import databroker -import matplotlib.pyplot as plt +from bluesky import plans as bp, plan_stubs as bps, RunEngine, suspenders # noqa: F401 +from bluesky.simulators import summarize_plan # noqa: F401 +from bluesky.callbacks.best_effort import BestEffortCallback # noqa: F401 +import databroker # noqa: F401 +import matplotlib.pyplot as plt # noqa: F401 -import haven +import haven # noqa: F401 # Prepare the haven instrument config = haven.load_config() diff --git a/pyproject.toml b/pyproject.toml index 08353756..109f4ba8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,3 +37,6 @@ firefly_cameras = "firefly.launcher:cameras" [build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" + +[tool.isort] +profile = "black" diff --git a/src/conftest.py b/src/conftest.py index 1ffdd468..7702039a 100644 --- a/src/conftest.py +++ b/src/conftest.py @@ -1,35 +1,38 @@ -from unittest import mock +import os import subprocess -import psutil from pathlib import Path -import os +from unittest import mock -from bluesky import RunEngine +import psutil + +# from pydm.data_plugins import plugin_modules, add_plugin +import pydm import pytest -from ophyd import DynamicDeviceComponent as DDC, Kind +from bluesky import RunEngine +from ophyd import DynamicDeviceComponent as DDC +from ophyd import Kind from ophyd.sim import ( + FakeEpicsSignal, + fake_device_cache, instantiate_fake_device, make_fake_device, - fake_device_cache, - FakeEpicsSignal, ) -from pydm.data_plugins import add_plugin from pytestqt.qt_compat import qt_api import haven +from firefly.application import FireflyApplication +from firefly.main_window import FireflyMainWindow from haven._iconfig import beamline_connected as _beamline_connected from haven.instrument.aerotech import AerotechStage from haven.instrument.aps import ApsMachine -from haven.instrument.shutter import Shutter from haven.instrument.camera import AravisDetector from haven.instrument.delay import EpicsSignalWithIO -from haven.instrument.dxp import DxpDetector, add_mcas as add_dxp_mcas +from haven.instrument.dxp import DxpDetector +from haven.instrument.dxp import add_mcas as add_dxp_mcas from haven.instrument.ion_chamber import IonChamber -from haven.instrument.xspress import Xspress3Detector, add_mcas as add_xspress_mcas -from firefly.application import FireflyApplication -from firefly.main_window import FireflyMainWindow -from firefly.ophyd_plugin import OphydPlugin - +from haven.instrument.shutter import Shutter +from haven.instrument.xspress import Xspress3Detector +from haven.instrument.xspress import add_mcas as add_xspress_mcas top_dir = Path(__file__).parent.resolve() haven_dir = top_dir / "haven" @@ -113,10 +116,7 @@ def kill_process(process_name): def sim_registry(monkeypatch): # mock out Ophyd connections so devices can be created modules = [ - haven.instrument.fluorescence_detector, - haven.instrument.monochromator, haven.instrument.ion_chamber, - haven.instrument.motor, haven.instrument.device, ] for mod in modules: @@ -124,16 +124,21 @@ def sim_registry(monkeypatch): monkeypatch.setattr( haven.instrument.ion_chamber, "caget", mock.AsyncMock(return_value="I0") ) - # Clean the registry so we can restore it later + # Save the registry so we can restore it later registry = haven.registry + use_typhos = registry.use_typhos objects_by_name = registry._objects_by_name objects_by_label = registry._objects_by_label registry.clear() # Run the test - yield registry - # Restore the previous registry components - registry._objects_by_name = objects_by_name - registry._objects_by_label = objects_by_label + try: + yield registry + finally: + # Restore the previous registry components + registry.clear(clear_typhos=True) + registry._objects_by_name = objects_by_name + registry._objects_by_label = objects_by_label + registry.use_typhos = use_typhos @pytest.fixture() @@ -265,7 +270,7 @@ def shutters(sim_registry): @pytest.fixture(scope="session") def pydm_ophyd_plugin(): - return add_plugin(OphydPlugin) + return pydm.data_plugins.plugin_for_address("sig://") qs_status = { diff --git a/src/firefly/__init__.py b/src/firefly/__init__.py index 288b43d1..f3ad9a95 100644 --- a/src/firefly/__init__.py +++ b/src/firefly/__init__.py @@ -1,3 +1,2 @@ -from . import display - -from .application import FireflyApplication +from . import display # noqa: F401 +from .application import FireflyApplication # noqa: F401 diff --git a/src/firefly/application.py b/src/firefly/application.py index f775d72c..54947097 100644 --- a/src/firefly/application.py +++ b/src/firefly/application.py @@ -1,29 +1,24 @@ import logging +import subprocess from collections import OrderedDict -from pathlib import Path -from dataclasses import dataclass, field -from typing import Optional, Union, Mapping, Sequence from functools import partial -import subprocess +from pathlib import Path +from typing import Mapping, Sequence -from qtpy import QtWidgets, QtCore -from qtpy.QtWidgets import QAction -from qtpy.QtCore import Slot, QThread, Signal, QObject -from PyQt5.QtWidgets import QStyleFactory -import qtawesome as qta import pydm +import pyqtgraph as pg +import qtawesome as qta from pydm.application import PyDMApplication -from pydm.display import load_file from pydm.utilities.stylesheet import apply_stylesheet -from bluesky_queueserver_api import BPlan -from bluesky_queueserver_api.zmq import REManagerAPI -import pyqtgraph as pg +from PyQt5.QtWidgets import QStyleFactory +from qtpy import QtCore, QtWidgets +from qtpy.QtCore import Signal +from qtpy.QtWidgets import QAction +from haven import HavenMotor, load_config, registry from haven.exceptions import ComponentNotFound -from haven import HavenMotor, registry, load_config -import haven + from .main_window import FireflyMainWindow, PlanMainWindow -from .ophyd_plugin import OphydPlugin from .queue_client import QueueClient, QueueClientThread, queueserver_api generator = type((x for x in [])) @@ -51,6 +46,8 @@ class FireflyApplication(PyDMApplication): show_runs_window_action: QtWidgets.QAction show_energy_window_action: QtWidgets.QAction show_bss_window_action: QtWidgets.QAction + show_voltmeters_window_action: QtWidgets.QAction + show_logs_window_action: QtWidgets.QAction launch_queuemonitor_action: QtWidgets.QAction # Keep track of motors @@ -174,6 +171,18 @@ def setup_window_actions(self): text="Scheduling (&BSS)", slot=self.show_bss_window, ) + # Launch ion chamber voltmeters window + self._setup_window_action( + action_name="show_voltmeters_window_action", + text="&Voltmeters", + slot=self.show_voltmeters_window, + ) + # Launch log window + self._setup_window_action( + action_name="show_logs_window_action", + text="Logs", + slot=self.show_logs_window, + ) # Launch energy window self._setup_window_action( action_name="show_energy_window_action", @@ -266,14 +275,13 @@ def _prepare_device_windows(self, device_label: str, attr_name: str): window_slots = [] setattr(self, f"{attr_name}_window_slots", window_slots) setattr(self, f"{attr_name}_windows", {}) - # if attr_name == "ion_chamber": - # breakpoint() for device in devices: + # Create the window action action = QtWidgets.QAction(self) action.setObjectName(f"actionShow_{attr_name}_{device.name}") action.setText(device.name) actions[device.name] = action - # Create a slot for opening the motor window + # Create a slot for opening the device window slot = getattr(self, f"show_{attr_name}_window") slot = partial(slot, device=device) action.triggered.connect(slot) @@ -341,7 +349,11 @@ def prepare_queue_client(self, api=None): thread = QueueClientThread() self._queue_thread = thread # Create the client object - client = QueueClient(api=api, autoplay_action=self.queue_autoplay_action, open_environment_action=self.queue_open_environment_action) + client = QueueClient( + api=api, + autoplay_action=self.queue_autoplay_action, + open_environment_action=self.queue_open_environment_action, + ) client.moveToThread(thread) thread.timer.timeout.connect(client.update) self._queue_client = client @@ -429,9 +441,7 @@ def connect_menu_signals(self, window): and setup code. """ - window.actionShow_Log_Viewer.triggered.connect(self.show_log_viewer_window) window.actionShow_Xafs_Scan.triggered.connect(self.show_xafs_scan_window) - window.actionShow_Voltmeters.triggered.connect(self.show_voltmeters_window) window.actionShow_Sample_Viewer.triggered.connect( self.show_sample_viewer_window ) @@ -540,7 +550,7 @@ def show_run_browser(self): ) @QtCore.Slot() - def show_log_viewer_window(self): + def show_logs_window(self): self.show_window(FireflyMainWindow, ui_dir / "log_viewer.ui", name="log_viewer") @QtCore.Slot() diff --git a/src/firefly/area_detector_overlay.ui b/src/firefly/area_detector_overlay.ui index 1ac415b2..450053de 100644 --- a/src/firefly/area_detector_overlay.ui +++ b/src/firefly/area_detector_overlay.ui @@ -44,7 +44,7 @@ - oph://${AD}.overlays.overlay_${OV}.use + sig://${AD}.overlays.overlay_${OV}.use @@ -61,7 +61,7 @@ - oph://${AD}.overlays.overlay_${OV}.shape + sig://${AD}.overlays.overlay_${OV}.shape @@ -75,7 +75,7 @@ - oph://${AD}.overlays.overlay_${OV}.position_y + sig://${AD}.overlays.overlay_${OV}.position_y Qt::Vertical @@ -100,7 +100,7 @@ - oph://${AD}.overlays.overlay_${OV}.position_x + sig://${AD}.overlays.overlay_${OV}.position_x 0 @@ -132,7 +132,7 @@ - oph://${AD}.overlays.overlay_${OV}.size_y + sig://${AD}.overlays.overlay_${OV}.size_y Qt::Vertical @@ -157,7 +157,7 @@ - oph://${AD}.overlays.overlay_${OV}.size_x + sig://${AD}.overlays.overlay_${OV}.size_x diff --git a/src/firefly/area_detector_roi.ui b/src/firefly/area_detector_roi.ui index 477048f9..568bdce5 100644 --- a/src/firefly/area_detector_roi.ui +++ b/src/firefly/area_detector_roi.ui @@ -50,7 +50,7 @@ NaN - oph://${AD}.stats${R}.mean_value + sig://${AD}.stats${R}.mean_value @@ -77,7 +77,7 @@ NaN - oph://${AD}.stats${R}.min_value + sig://${AD}.stats${R}.min_value @@ -104,7 +104,7 @@ NaN - oph://${AD}.stats${R}.max_value + sig://${AD}.stats${R}.max_value @@ -132,7 +132,7 @@ Show - oph://${AD}.overlays.overlay_${R}.use + sig://${AD}.overlays.overlay_${R}.use @@ -144,7 +144,7 @@ - oph://${AD}.roi${R}.min_xyz.min_y + sig://${AD}.roi${R}.min_xyz.min_y Qt::Vertical @@ -169,7 +169,7 @@ - oph://${AD}.roi${R}.min_xyz.min_x + sig://${AD}.roi${R}.min_xyz.min_x 0 @@ -201,7 +201,7 @@ - oph://${AD}.roi${R}.size.y + sig://${AD}.roi${R}.size.y Qt::Vertical @@ -226,7 +226,7 @@ - oph://${AD}.roi${R}.size.x + sig://${AD}.roi${R}.size.x diff --git a/src/firefly/area_detector_viewer.py b/src/firefly/area_detector_viewer.py index f0400be3..10ff75c4 100644 --- a/src/firefly/area_detector_viewer.py +++ b/src/firefly/area_detector_viewer.py @@ -1,16 +1,13 @@ import logging -import subprocess +import sys -import pyqtgraph -import pydm import numpy as np -import matplotlib.pyplot as plt +import pydm +import pyqtgraph import haven from firefly import display -import sys - np.set_printoptions(threshold=sys.maxsize) diff --git a/src/firefly/area_detector_viewer.ui b/src/firefly/area_detector_viewer.ui index 675c9fe9..07398350 100644 --- a/src/firefly/area_detector_viewer.ui +++ b/src/firefly/area_detector_viewer.ui @@ -130,7 +130,7 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - oph://${AD}.cam.array_size.array_size_y + sig://${AD}.cam.array_size.array_size_y @@ -153,7 +153,7 @@ 1224 - oph://${AD}.cam.array_size.array_size_x + sig://${AD}.cam.array_size.array_size_x @@ -206,7 +206,7 @@ [] - oph://${AD}.cam.gain + sig://${AD}.cam.gain QSlider::TicksBelow @@ -234,7 +234,7 @@ Auto - oph://${AD}.cam.gain_auto + sig://${AD}.cam.gain_auto 1 @@ -257,7 +257,7 @@ [] - oph://${AD}.cam.acquire_time + sig://${AD}.cam.acquire_time QSlider::TicksBelow @@ -282,7 +282,7 @@ Auto - oph://${AD}.cam.acquire_time_auto + sig://${AD}.cam.acquire_time_auto 1 @@ -313,7 +313,7 @@ false - oph://${AD}.cam.acquire + sig://${AD}.cam.acquire false @@ -356,7 +356,7 @@ [{"name": "enable_acquire_buttons", "property": "Enable", "initial_value": "", "expression": "ch[0] == 1", "channels": [{"channel": "${PREFIX}cam1:Acquire", "trigger": true, "use_enum": false}]}] - oph://${AD}.cam.acquire + sig://${AD}.cam.acquire 0 diff --git a/src/firefly/bss.py b/src/firefly/bss.py index ebcd5d0a..380e0a0c 100644 --- a/src/firefly/bss.py +++ b/src/firefly/bss.py @@ -1,10 +1,10 @@ import logging from functools import lru_cache -from apsbss import apsbss -from qtpy.QtGui import QStandardItemModel, QStandardItem -from qtpy.QtCore import Signal, Slot import qtawesome as qta +from apsbss import apsbss +from qtpy.QtCore import Signal +from qtpy.QtGui import QStandardItem, QStandardItemModel import haven from firefly import display diff --git a/src/firefly/bss.ui b/src/firefly/bss.ui index 7dfaf67c..a990b370 100644 --- a/src/firefly/bss.ui +++ b/src/firefly/bss.ui @@ -88,7 +88,7 @@ 688743 - oph://bss_proposal_proposal_id + sig://bss_proposal_proposal_id @@ -105,7 +105,7 @@ - oph://bss_proposal_title + sig://bss_proposal_title PyDMLineEdit::String @@ -127,7 +127,7 @@ - oph://bss_proposal_start_date + sig://bss_proposal_start_date PyDMLineEdit::String @@ -147,7 +147,7 @@ - oph://bss_proposal_end_date + sig://bss_proposal_end_date PyDMLineEdit::String @@ -169,7 +169,7 @@ - oph://bss_proposal_user_last_names + sig://bss_proposal_user_last_names PyDMLineEdit::String @@ -189,7 +189,7 @@ - oph://bss_proposal_user_badges + sig://bss_proposal_user_badges PyDMLineEdit::String @@ -209,7 +209,7 @@ - oph://bss_proposal_mail_in_flag + sig://bss_proposal_mail_in_flag @@ -226,7 +226,7 @@ - oph://bss_proposal_proprietary_flag + sig://bss_proposal_proprietary_flag @@ -303,7 +303,7 @@ 257794 - oph://bss_esaf_esaf_id + sig://bss_esaf_esaf_id @@ -323,7 +323,7 @@ Approved - oph://bss_esaf_esaf_status + sig://bss_esaf_esaf_status @@ -340,7 +340,7 @@ - oph://bss_esaf_title + sig://bss_esaf_title PyDMLineEdit::String @@ -362,7 +362,7 @@ - oph://bss_esaf_start_date + sig://bss_esaf_start_date PyDMLineEdit::String @@ -382,7 +382,7 @@ - oph://bss_esaf_end_date + sig://bss_esaf_end_date PyDMLineEdit::String @@ -404,7 +404,7 @@ - oph://bss_esaf_user_last_names + sig://bss_esaf_user_last_names PyDMLineEdit::String @@ -424,7 +424,7 @@ - oph://bss_esaf_user_badges + sig://bss_esaf_user_badges PyDMLineEdit::String diff --git a/src/firefly/button.py b/src/firefly/button.py index 5e6bafdf..398e9b99 100644 --- a/src/firefly/button.py +++ b/src/firefly/button.py @@ -1,6 +1,6 @@ +import qtawesome as qta from qtpy import QtWidgets from qtpy.QtGui import QIcon -import qtawesome as qta class RevealButton(QtWidgets.QPushButton): diff --git a/src/firefly/camera.py b/src/firefly/camera.py index 0bec98c6..2c2ed4f3 100644 --- a/src/firefly/camera.py +++ b/src/firefly/camera.py @@ -1,19 +1,13 @@ +import logging from enum import IntEnum from pathlib import Path -import datetime as dt -import subprocess -import logging -import os - -import haven # from pydm.data_plugins.epics_plugin import EPICSPlugin from pydm.widgets.channel import PyDMChannel -from qtpy.QtGui import QColor from qtpy.QtCore import Slot +from qtpy.QtGui import QColor -from firefly import display, FireflyApplication - +from firefly import FireflyApplication, display log = logging.getLogger(__name__) diff --git a/src/firefly/camera.ui b/src/firefly/camera.ui index 2f2c5a0f..7babc1c0 100644 --- a/src/firefly/camera.ui +++ b/src/firefly/camera.ui @@ -59,7 +59,7 @@ true - oph://${CAMERA}.cam.acquire + sig://${CAMERA}.cam.acquire diff --git a/src/firefly/cameras.py b/src/firefly/cameras.py index 1491200d..58f93f55 100644 --- a/src/firefly/cameras.py +++ b/src/firefly/cameras.py @@ -2,11 +2,10 @@ import logging from pydm.widgets import PyDMEmbeddedDisplay -import haven +import haven from firefly import display - log = logging.getLogger(__name__) diff --git a/src/firefly/detector_list.py b/src/firefly/detector_list.py index 8d58fa95..8557c68b 100644 --- a/src/firefly/detector_list.py +++ b/src/firefly/detector_list.py @@ -1,4 +1,4 @@ -from PyQt5.QtGui import QStandardItemModel, QStandardItem +from PyQt5.QtGui import QStandardItem, QStandardItemModel from qtpy.QtWidgets import QListView from haven import registry diff --git a/src/firefly/display.py b/src/firefly/display.py index 183e4e2c..6cc60671 100644 --- a/src/firefly/display.py +++ b/src/firefly/display.py @@ -1,10 +1,10 @@ -from typing import Sequence import subprocess from pathlib import Path +from typing import Sequence -from qtpy.QtCore import Signal, Slot -from qtpy import QtWidgets from pydm import Display +from qtpy import QtWidgets +from qtpy.QtCore import Signal, Slot class FireflyDisplay(Display): diff --git a/src/firefly/energy.py b/src/firefly/energy.py index 7f15620c..440bfdb4 100644 --- a/src/firefly/energy.py +++ b/src/firefly/energy.py @@ -1,13 +1,12 @@ import logging -from qtpy import QtWidgets, QtCore +import qtawesome as qta from bluesky_queueserver_api import BPlan -from haven import registry, load_config, exceptions +from qtpy import QtCore, QtWidgets from xraydb.xraydb import XrayDB -import qtawesome as qta from firefly import display - +from haven import exceptions, load_config, registry log = logging.getLogger(__name__) diff --git a/src/firefly/energy.ui b/src/firefly/energy.ui index d6321def..489d190a 100644 --- a/src/firefly/energy.ui +++ b/src/firefly/energy.ui @@ -216,7 +216,7 @@ - oph://monochromator_mode + sig://monochromator_mode @@ -254,7 +254,7 @@ false - oph://monochromator_energy_user_readback + sig://monochromator_energy_user_readback @@ -383,7 +383,7 @@ true - oph://undulator_gap + sig://undulator_gap @@ -440,7 +440,7 @@ true - oph://undulator_energy + sig://undulator_energy diff --git a/src/firefly/ion_chamber.ui b/src/firefly/ion_chamber.ui index 96548d2c..a9ce472d 100644 --- a/src/firefly/ion_chamber.ui +++ b/src/firefly/ion_chamber.ui @@ -48,7 +48,7 @@ The name of this ion chamber. - oph://${IC}.description + sig://${IC}.description false @@ -103,7 +103,7 @@ - [{"name": "Gain button lower range", "property": "Enable", "initial_value": "True", "expression": "ch[0] < 27", "channels": [{"channel": "oph://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": "If the sensitivity is at its highest setting, disable the button so users don't click it unnecessarily."}] + [{"name": "Gain button lower range", "property": "Enable", "initial_value": "True", "expression": "ch[0] < 27", "channels": [{"channel": "sig://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": "If the sensitivity is at its highest setting, disable the button so users don't click it unnecessarily."}] false @@ -118,7 +118,7 @@ false - oph://${IC}.preamp.sensitivity_level + sig://${IC}.preamp.sensitivity_level false @@ -155,7 +155,7 @@ - oph://${IC}.preamp.sensitivity_value + sig://${IC}.preamp.sensitivity_value @@ -165,7 +165,7 @@ - oph://${IC}.preamp.sensitivity_unit + sig://${IC}.preamp.sensitivity_unit @@ -196,7 +196,7 @@ - [{"name": "Gain button upper range", "property": "Enable", "initial_value": "True", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": ""}] + [{"name": "Gain button upper range", "property": "Enable", "initial_value": "True", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": ""}] false @@ -211,7 +211,7 @@ false - oph://${IC}.preamp.sensitivity_level + sig://${IC}.preamp.sensitivity_level false @@ -274,7 +274,7 @@ The gain of the amplifier - oph://${IC}.preamp.gain_db + sig://${IC}.preamp.gain_db false @@ -359,7 +359,7 @@ - oph://${IC}.preamp.offset_on + sig://${IC}.preamp.offset_on @@ -369,7 +369,7 @@ - [{"name": "Offset disabled", "property": "Enable", "initial_value": "False", "expression": "bool(ch[0])", "channels": [{"channel": "oph://${IC}.preamp.offset_on", "trigger": true, "use_enum": true}], "notes": ""}] + [{"name": "Offset disabled", "property": "Enable", "initial_value": "False", "expression": "bool(ch[0])", "channels": [{"channel": "sig://${IC}.preamp.offset_on", "trigger": true, "use_enum": true}], "notes": ""}] false @@ -384,7 +384,7 @@ false - oph://${IC}.preamp.offset_sign + sig://${IC}.preamp.offset_sign @@ -406,7 +406,7 @@ false - oph://${IC}.preamp.offset_value + sig://${IC}.preamp.offset_value @@ -428,7 +428,7 @@ false - oph://${IC}.preamp.offset_unit + sig://${IC}.preamp.offset_unit @@ -473,7 +473,7 @@ false - oph://${IC}.preamp.set_all + sig://${IC}.preamp.set_all false @@ -571,7 +571,7 @@ The calculate voltage based on scaler counts and clock speed. - oph://${IC}.volts + sig://${IC}.volts false @@ -640,7 +640,7 @@ The calculated current based on the voltage and pre-amp settings. - oph://${IC}.amps + sig://${IC}.amps PyDMLabel::Exponential @@ -710,7 +710,7 @@ false - oph://${IC}.exposure_time + sig://${IC}.exposure_time @@ -771,7 +771,7 @@ #e## - oph://${IC}.frequency + sig://${IC}.frequency PyDMLabel::Exponential @@ -818,7 +818,7 @@ <html><head/><body><p>The number of counts measured by the scaler.</p><p><br/></p><p>This is the counts produced by the voltage-to-frequency convertor, and <span style=" font-weight:600;">not</span> the photon count.</p></body></html> - oph://${IC}.counts + sig://${IC}.counts @@ -833,7 +833,7 @@ Count - oph://${IC}.count + sig://${IC}.count 1 @@ -849,7 +849,7 @@ Autocount - oph://${IC}.auto_count + sig://${IC}.auto_count @@ -876,7 +876,7 @@ - oph://${IC}.gate + sig://${IC}.gate @@ -886,7 +886,7 @@ <html><head/><body><p>Stop collecting data when the tick counts for this scaler channel reaches a certain preset value.</p><p>To help decide this value, consider that the clock gives the number of counts that a 10V signal produces in 1 sec. So if the clock is 1e7 Hz, then a <span style=" font-style:italic;">preset count</span> of 2.5e6 would be the equivalent of counting a 2.5V signal for 1 sec.</p><p>The scaler will stop when either <span style=" font-style:italic;">acquire time</span> is reached, or <span style=" font-style:italic;">preset count</span> is reached for any channel on that scaler.</p><p>A <span style=" font-style:italic;">preset count</span> of 0 will disable this behavior.</p></body></html> - [{"name": "Disable Present Counts", "property": "Enable", "initial_value": "True", "expression": "ch[0]", "channels": [{"channel": "oph://${IC}.gate", "trigger": true, "use_enum": false}], "notes": "The preset-counts should only be editable when the channel is set to respond to the gate. If users really want to set it but disable the gate, then they'll need to just check the box first."}] + [{"name": "Disable Present Counts", "property": "Enable", "initial_value": "True", "expression": "ch[0]", "channels": [{"channel": "sig://${IC}.gate", "trigger": true, "use_enum": false}], "notes": "The preset-counts should only be editable when the channel is set to respond to the gate. If users really want to set it but disable the gate, then they'll need to just check the box first."}] 0 @@ -910,7 +910,7 @@ false - oph://${IC}.preset_count + sig://${IC}.preset_count @@ -1007,7 +1007,7 @@ The measured voltage output from the pre-amp. - oph://${IC}.voltmeter.volts + sig://${IC}.voltmeter.volts PyDMLabel::Decimal @@ -1078,7 +1078,7 @@ The calculated current based on the voltage and pre-amp settings. - oph://${IC}.voltmeter.amps + sig://${IC}.voltmeter.amps PyDMLabel::Exponential @@ -1121,7 +1121,7 @@ How often to report new signals for this voltmeter. - oph://${IC}.voltmeter.scanning_rate + sig://${IC}.voltmeter.scanning_rate diff --git a/src/firefly/launcher.py b/src/firefly/launcher.py index c284d535..b026ad6f 100644 --- a/src/firefly/launcher.py +++ b/src/firefly/launcher.py @@ -1,12 +1,11 @@ -import time import argparse import cProfile import logging import pstats import sys +import time from pathlib import Path - import haven @@ -25,20 +24,14 @@ def main(default_fullscreen=False, default_display="status"): otherwise we get the following error if someone adds a WebView at Designer: ImportError: QtWebEngineWidgets must be imported before a QCoreApplication instance is created """ - from qtpy import QtWebEngineWidgets except ImportError: logger.debug("QtWebEngine is not supported.") - from qtpy.QtWidgets import QSplashScreen - from .application import FireflyApplication - from qtpy.QtGui import QPixmap from qtpy import QtCore + from qtpy.QtGui import QPixmap + from qtpy.QtWidgets import QSplashScreen - # Add plugins for handling ophyd objects - from pydm.data_plugins import add_plugin - from .ophyd_plugin import OphydPlugin - - add_plugin(OphydPlugin) + from .application import FireflyApplication # Set up splash screen fake_app = FireflyApplication(sys.argv) @@ -63,7 +56,6 @@ def main(default_fullscreen=False, default_display="status"): setup_renderer() - import pydm from pydm.utilities.macro import parse_macro_string parser = argparse.ArgumentParser(description="Python Display Manager") @@ -76,7 +68,10 @@ def main(default_fullscreen=False, default_display="status"): parser.add_argument( "--no-instrument", action="store_true", - help="Do not try to create devices. Useful for development if much beamline hardware is offline.", + help=( + "Do not try to create devices. Useful for development if much beamline" + " hardware is offline." + ), ) parser.add_argument( "--perfmon", diff --git a/src/firefly/main_window.py b/src/firefly/main_window.py index a2b0409f..340bea90 100644 --- a/src/firefly/main_window.py +++ b/src/firefly/main_window.py @@ -1,14 +1,13 @@ import logging -from pathlib import Path import warnings +from pathlib import Path +from pydm import data_plugins from pydm.main_window import PyDMMainWindow # from qtpy.QtCore import Slot from qtpy import QtCore, QtGui, QtWidgets -from pydm import data_plugins -from haven.instrument import motor -from haven.instrument import motor + from haven import load_config log = logging.getLogger(__name__) @@ -107,6 +106,8 @@ def customize_ui(self): # Connect signals to the status bar app.queue_environment_state_changed.connect(self.ui.environment_label.setText) app.queue_re_state_changed.connect(self.ui.re_label.setText) + # Log viewer window + self.ui.menuView.addAction(app.show_logs_window_action) # Setup menu self.ui.menuSetup = QtWidgets.QMenu(self.ui.menubar) self.ui.menuSetup.setObjectName("menuSetup") @@ -120,36 +121,15 @@ def customize_ui(self): for action in app.queue_action_group.actions(): self.ui.queue_menu.addAction(action) self.ui.queue_menu.addSeparator() + # Queue settings for the queue client + self.ui.queue_menu.addAction(app.launch_queuemonitor_action) self.ui.queue_menu.addAction(app.queue_autoplay_action) self.ui.queue_menu.addAction(app.queue_open_environment_action) - self.ui.menuView.addAction(app.launch_queuemonitor_action) - # Log viewer window - self.add_menu_action( - action_name="actionShow_Log_Viewer", text="Logs", menu=self.ui.menuView - ) # Positioners menu self.ui.menuPositioners = QtWidgets.QMenu(self.ui.menubar) self.ui.menuPositioners.setObjectName("menuPositioners") self.ui.menuPositioners.setTitle("&Positioners") self.ui.menubar.addAction(self.ui.menuPositioners.menuAction()) - # Detectors menu - self.ui.menuDetectors = QtWidgets.QMenu(self.ui.menubar) - self.ui.menuDetectors.setObjectName("menuDetectors") - self.ui.menuDetectors.setTitle("&Detectors") - self.ui.menubar.addAction(self.ui.menuDetectors.menuAction()) - # Scans menu - self.ui.menuScans = QtWidgets.QMenu(self.ui.menubar) - self.ui.menuScans.setObjectName("menuScans") - self.ui.menuScans.setTitle("Scans") - self.ui.menubar.addAction(self.ui.menuScans.menuAction()) - # Add entries for general scan management - self.ui.menuScans.addAction(app.launch_queuemonitor_action) - self.ui.menuScans.addAction(app.show_run_browser_action) - self.ui.menuScans.addSeparator() - # XAFS scan window - self.add_menu_action( - action_name="actionShow_Log_Viewer", text="Logs", menu=self.ui.menuView - ) # Sample viewer self.add_menu_action( action_name="actionShow_Sample_Viewer", @@ -173,36 +153,32 @@ def customize_ui(self): text="&XAFS Scan", menu=self.ui.menuScans, ) - # Auto-play setting for the queue client - if hasattr(app, "queue_autoplay_action"): - self.ui.menuScans.addAction(app.queue_autoplay_action) + # Add entries for general scan management + self.ui.menuScans.addSeparator() + self.ui.menuScans.addAction(app.show_run_browser_action) # Detectors menu - self.ui.menuDetectors = QtWidgets.QMenu(self.ui.menubar) - self.ui.menuDetectors.setObjectName("menuDetectors") - self.ui.menuDetectors.setTitle("&Detectors") - self.ui.menubar.addAction(self.ui.menuDetectors.menuAction()) + self.ui.detectors_menu = QtWidgets.QMenu(self.ui.menubar) + self.ui.detectors_menu.setObjectName("detectors_menu") + self.ui.detectors_menu.setTitle("&Detectors") + self.ui.menubar.addAction(self.ui.detectors_menu.menuAction()) # Voltmeters window - self.add_menu_action( - action_name="actionShow_Voltmeters", - text="&Voltmeters", - menu=self.ui.menuDetectors, - ) + self.ui.detectors_menu.addAction(app.show_voltmeters_window_action) # Add actions to the motors sub-menus for action in app.motor_actions: self.ui.menuMotors.addAction(action) # Add an ion chamber sub-menu - self.ui.menuIonChambers = QtWidgets.QMenu(self.ui.menubar) - self.ui.menuIonChambers.setObjectName("menuIonChambers") - self.ui.menuIonChambers.setTitle("&Ion Chambers") - self.ui.menuDetectors.addAction(self.ui.menuIonChambers.menuAction()) + self.ui.ion_chambers_menu = QtWidgets.QMenu(self.ui.menubar) + self.ui.ion_chambers_menu.setObjectName("ion_chambers_menu") + self.ui.ion_chambers_menu.setTitle("&Ion Chambers") + self.ui.detectors_menu.addAction(self.ui.ion_chambers_menu.menuAction()) # Add actions for the individual ion chambers for action in app.ion_chamber_actions.values(): - self.ui.menuIonChambers.addAction(action) + self.ui.ion_chambers_menu.addAction(action) # Cameras sub-menu self.ui.menuCameras = QtWidgets.QMenu(self.ui.menubar) self.ui.menuCameras.setObjectName("menuCameras") self.ui.menuCameras.setTitle("Cameras") - self.ui.menuDetectors.addAction(self.ui.menuCameras.menuAction()) + self.ui.detectors_menu.addAction(self.ui.menuCameras.menuAction()) # Add actions to the cameras sub-menus self.ui.menuCameras.addAction(app.show_cameras_window_action) self.ui.menuCameras.addSeparator() @@ -211,15 +187,15 @@ def customize_ui(self): # Add area detectors to detectors menu ad_actions = app.area_detector_actions.values() if len(ad_actions) > 0: - self.ui.menuDetectors.addSeparator() + self.ui.detectors_menu.addSeparator() for action in ad_actions: - self.ui.menuDetectors.addAction(action) + self.ui.detectors_menu.addAction(action) # Add XRF detectors to detectors menu xrf_actions = app.xrf_detector_actions.values() if len(xrf_actions) > 0: - self.ui.menuDetectors.addSeparator() + self.ui.detectors_menu.addSeparator() for action in xrf_actions: - self.ui.menuDetectors.addAction(action) + self.ui.detectors_menu.addAction(action) # Add other menu actions self.ui.menuView.addAction(app.show_status_window_action) self.ui.menuSetup.addAction(app.show_bss_window_action) @@ -245,9 +221,7 @@ def update_window_title(self): def export_actions(self): """Expose specific signals that might be useful for responding to window changes.""" - self.actionShow_Log_Viewer = self.ui.actionShow_Log_Viewer self.actionShow_Xafs_Scan = self.ui.actionShow_Xafs_Scan - self.actionShow_Voltmeters = self.ui.actionShow_Voltmeters class PlanMainWindow(FireflyMainWindow): diff --git a/src/firefly/motor.py b/src/firefly/motor.py index 292afbea..bace9cac 100644 --- a/src/firefly/motor.py +++ b/src/firefly/motor.py @@ -1,5 +1,3 @@ -import warnings - import haven from firefly import display diff --git a/src/firefly/motor.ui b/src/firefly/motor.ui index 1a3fa488..44d49957 100644 --- a/src/firefly/motor.ui +++ b/src/firefly/motor.ui @@ -35,7 +35,7 @@ Qt::AlignCenter - oph://${MOTOR}_description + sig://${MOTOR}_description @@ -59,7 +59,7 @@ true - oph://${MOTOR}.user_readback + sig://${MOTOR}.user_readback @@ -92,7 +92,7 @@ - [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${MOTOR}_low_limit_switch", "trigger": true, "use_enum": false}]}] + [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${MOTOR}_low_limit_switch", "trigger": true, "use_enum": false}]}] false @@ -101,7 +101,7 @@ true - oph://${MOTOR}_low_limit_switch + sig://${MOTOR}_low_limit_switch @@ -145,10 +145,10 @@ - [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${MOTOR}_soft_limit_violation", "trigger": true, "use_enum": false}]}] + [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${MOTOR}_soft_limit_violation", "trigger": true, "use_enum": false}]}] - oph://${MOTOR}_soft_limit_violation + sig://${MOTOR}_soft_limit_violation @@ -180,7 +180,7 @@ 5000.0281 - oph://${MOTOR}.user_setpoint + sig://${MOTOR}.user_setpoint @@ -195,7 +195,7 @@ - [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${MOTOR}_high_limit_switch", "trigger": true, "use_enum": false}]}] + [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${MOTOR}_high_limit_switch", "trigger": true, "use_enum": false}]}] false @@ -204,7 +204,7 @@ true - oph://${MOTOR}_high_limit_switch + sig://${MOTOR}_high_limit_switch @@ -248,10 +248,10 @@ - [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${MOTOR}_soft_limit_violation", "trigger": true, "use_enum": false}]}] + [{"name": "limit_autohide", "property": "Visible", "initial_value": "False", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${MOTOR}_soft_limit_violation", "trigger": true, "use_enum": false}]}] - oph://${MOTOR}_soft_limit_violation + sig://${MOTOR}_soft_limit_violation @@ -298,7 +298,7 @@ Stop - oph://${MOTOR}.motor_stop + sig://${MOTOR}.motor_stop 1 @@ -345,7 +345,7 @@ - oph://${MOTOR}_tweak_reverse + sig://${MOTOR}_tweak_reverse 1 @@ -379,7 +379,7 @@ Jog step - oph://${MOTOR}.tweak_value + sig://${MOTOR}.tweak_value @@ -415,7 +415,7 @@ - oph://${MOTOR}_tweak_forward + sig://${MOTOR}_tweak_forward 1 diff --git a/src/firefly/ophyd_plugin.py b/src/firefly/ophyd_plugin.py deleted file mode 100644 index f416c85d..00000000 --- a/src/firefly/ophyd_plugin.py +++ /dev/null @@ -1,175 +0,0 @@ -import logging -import warnings - -import numpy as np -from qtpy.QtCore import Qt, Slot, QTimer -from qtpy.QtWidgets import QApplication -from ophyd import OphydObject -from haven import registry, exceptions -from pydm.data_plugins import add_plugin -from pydm.data_plugins.plugin import PyDMConnection, PyDMPlugin - - -log = logging.getLogger(__name__) - - -class Connection(PyDMConnection): - """A pydm connection for hardware abstraction through Ophyd objects. - - This makes use of Haven's instrument registry, and the channel - address should be the name of the device to be manipulated as - known to the registry. For example, if you have an epics motor - device named "stage_vert", then to manipulate the setpoint, use - "oph://stage_vert.user_setpoint", and for retrieving the readback - value, use "oph://stage_vert.user_readback". The exact name will - depend on the specifics of the ophyd device being used. - - """ - - _cpt: OphydObject = None - _ctrl_vars: dict = {} - _known_signals: list - _cids: dict - - def __init__(self, channel, address, protocol=None, parent=None): - name = address - self._cids = {} - self._known_signals = [] - super().__init__(channel, address, protocol, parent) - # Resolve the device based on the ohpyd name - try: - self._cpt = registry.find(address) - except (AttributeError, exceptions.ComponentNotFound): - log.warning(f"Couldn't find ophyd plugin device: {address}") - else: - log.debug(f"Found device: {address}: {self._cpt.name}") - # Listen for changes - self.prepare_subscriptions() - self.add_listener(channel) # Think this might not be needed, but should check - - def prepare_subscriptions(self): - """Set up routines to respond to changes in the ophyd object.""" - if self._cpt is not None: - log.debug(f"Preparing subscriptions for {self._cpt.name}") - self._cids["meta"] = self._cpt.subscribe( - self.update_ctrl_vars, event_type="meta", run=False - ) - event_type = self._cpt._default_sub - self._cids[event_type] = self._cpt.subscribe( - self.send_new_value, event_type=event_type, run=False - ) - - def send_new_value(self, *args, **kwargs): - if "value" in kwargs.keys(): - value = kwargs["value"] - log.debug(f"Received new value for {self._cpt.name}: {value}") - else: - log.debug( - f"Did not receive a new value. Skipping update for {self._cpt.name}." - ) - return - log.debug(f"Sending new {type(value)} value for {self._cpt.name}: {value}") - self.new_value_signal[type(value)].emit(value) - - def update_ctrl_vars(self, *args, **kwargs): - # Emit signal if variable has changed - var_signals = { - "connected": self.connection_state_signal, - "severity": self.new_severity_signal, - "write_access": self.write_access_signal, - "enum_strs": self.enum_strings_signal, - "units": self.unit_signal, - "precision": self.prec_signal, - "lower_ctrl_limit": self.lower_ctrl_limit_signal, - "upper_ctrl_limit": self.upper_ctrl_limit_signal, - } - if hasattr(self, "timestamp_signal"): - # The timestamp_signal is a recent addition to PyDM - var_signals["timestamp"] = self.timestamp_signal - # Process the individual control variable arguments - for key, signal in var_signals.items(): - if kwargs.get(key) is not None: - # Use the argument value - val = kwargs[key] - else: - log.debug( - f"Could not find {key} control variable for {self._cpt.name}." - ) - continue - # Emit the new value if is different from last time - if val != self._ctrl_vars.get(key, None): - log.debug(f"Emitting new {key}: {val}") - signal.emit(val) - self._ctrl_vars[key] = val - - def add_listener(self, channel): - super(Connection, self).add_listener(channel) - # Clear cached control variables so they can get remitted - self._ctrl_vars = {} - # If the channel is used for writing to components, hook it up - sig = channel.value_signal - is_new_signal = sig not in self._known_signals - if sig is not None and is_new_signal: - # Connect new signals - for dtype in [float, int, str, np.ndarray]: - try: - sig[dtype].connect(self.set_value, Qt.QueuedConnection) - except KeyError: - pass - self._known_signals.append(sig) - # Run the callbacks to make sure the new listener gets notified - self.run_callbacks() - - def run_callbacks(self): - """Run the existing callbacks of the Ophyd object.""" - if self._cpt is None: - self.connection_state_signal.emit(False) - else: - cpt = self._cpt - cpt.get(use_monitor=False) - for event_type in [cpt._default_sub, "meta"]: - cached = cpt._args_cache[event_type] - log.debug(f"Running {event_type} callbacks: {cached}") - if cached is not None: - args, kwargs = cached - elif event_type == "meta": - args = () - kwargs = cpt.metadata - else: - continue - cid = self._cids[event_type] - callback = cpt._callbacks[event_type][cid] - callback(*args, **kwargs) - - def close(self): - """Remove any callbacks previously set up for this connection.""" - if self._cpt is not None: - for cid in self._cids.values(): - self._cpt.unsubscribe(cid) - - @Slot(float) - @Slot(int) - @Slot(str) - @Slot(np.ndarray) - def set_value(self, new_value): - if self._cpt is None: - log.warning( - "Cannot set value {new_value} for missing component {self._cpt.name}" - ) - else: - log.debug(f"Setting new value for {self._cpt.name}: {new_value}") - try: - return self._cpt.set(new_value, timeout=1) - except RuntimeError: - msg = ( - f"Previous set for {self._cpt.name} still in progress, " - f"skipping set to {new_value}" - ) - warnings.warn(msg) - log.warning(msg) - return None - - -class OphydPlugin(PyDMPlugin): - protocol = "oph" - connection_class = Connection diff --git a/src/firefly/plans/count.py b/src/firefly/plans/count.py index bd4fa917..4c06281c 100644 --- a/src/firefly/plans/count.py +++ b/src/firefly/plans/count.py @@ -1,6 +1,5 @@ import logging -from qtpy import QtWidgets from bluesky_queueserver_api import BPlan from firefly import display diff --git a/src/firefly/queue_button.py b/src/firefly/queue_button.py index d287464a..0441f23d 100644 --- a/src/firefly/queue_button.py +++ b/src/firefly/queue_button.py @@ -1,7 +1,7 @@ """A QPushButton that responds to the state of the queue server.""" -from qtpy import QtWidgets, QtGui import qtawesome as qta +from qtpy import QtGui, QtWidgets from firefly import FireflyApplication @@ -26,8 +26,7 @@ def handle_queue_status_change(self, status: dict): if status["re_state"] == "idle" and app.queue_autoplay_action.isChecked(): # Will play immediately self.setStyleSheet( - "background-color: rgb(25, 135, 84);\n" - "border-color: rgb(25, 135, 84);" + "background-color: rgb(25, 135, 84);\nborder-color: rgb(25, 135, 84);" ) self.setIcon(qta.icon("fa5s.play")) self.setText("Run") @@ -35,8 +34,7 @@ def handle_queue_status_change(self, status: dict): elif status["worker_environment_exists"]: # Will be added to the queue self.setStyleSheet( - "background-color: rgb(0, 123, 255);\n" - "border-color: rgb(0, 123, 255);" + "background-color: rgb(0, 123, 255);\nborder-color: rgb(0, 123, 255);" ) self.setIcon(qta.icon("fa5s.list")) self.setText("Add to Queue") diff --git a/src/firefly/queue_client.py b/src/firefly/queue_client.py index d98bf935..d498392c 100644 --- a/src/firefly/queue_client.py +++ b/src/firefly/queue_client.py @@ -1,16 +1,15 @@ -import time -from typing import Optional import logging +import time import warnings +from typing import Optional -from qtpy.QtWidgets import QAction -from qtpy.QtCore import QThread, QObject, Signal, Slot, QTimer +from bluesky_queueserver_api import comm_base from bluesky_queueserver_api.zmq import REManagerAPI -from bluesky_queueserver_api import BPlan, comm_base +from qtpy.QtCore import QObject, QThread, QTimer, Signal, Slot +from qtpy.QtWidgets import QAction from haven import load_config - log = logging.getLogger() @@ -30,6 +29,7 @@ class QueueClientThread(QThread): :py:cls:`QueueClientThread.timer.timeout()` signal. """ + timer: QTimer def __init__(self, *args, poll_time=1000, **kwargs): @@ -217,9 +217,8 @@ def _check_queue_status(self, force: bool = False): if is_new or has_changed or force: signal.emit(new_status[key]) # Check for new available devices - if ( - new_status["devices_allowed_uid"] - != self._last_queue_status.get("devices_allowed_uid") + if new_status["devices_allowed_uid"] != self._last_queue_status.get( + "devices_allowed_uid" ): self.update_devices() # check the whole status to see if it's changed @@ -236,5 +235,6 @@ def update_devices(self): self.devices_changed.emit(devices) else: log.warning( - f"Could not poll devices_allowed: {response.get('msg', 'reason unknown.')}" + "Could not poll devices_allowed:" + f" {response.get('msg', 'reason unknown.')}" ) diff --git a/src/firefly/run_browser.py b/src/firefly/run_browser.py index 59bd0765..b618a0cb 100644 --- a/src/firefly/run_browser.py +++ b/src/firefly/run_browser.py @@ -1,24 +1,20 @@ import logging -import datetime as dt -from typing import Sequence -import warnings -import yaml -from httpx import HTTPStatusError, PoolTimeout -from contextlib import contextmanager from itertools import count +from typing import Sequence import numpy as np -from qtpy.QtWidgets import QWidget -from qtpy.QtGui import QStandardItemModel, QStandardItem -from qtpy.QtCore import Signal, Slot, QThread, Qt -from pyqtgraph import PlotItem, GraphicsLayoutWidget, PlotWidget, PlotDataItem import qtawesome as qta +import yaml from matplotlib.colors import TABLEAU_COLORS from pydantic.error_wrappers import ValidationError +from pyqtgraph import PlotItem, PlotWidget +from qtpy.QtCore import Qt, QThread, Signal +from qtpy.QtGui import QStandardItem, QStandardItemModel +from qtpy.QtWidgets import QWidget -from firefly import display, FireflyApplication +from haven import exceptions +from firefly import display from firefly.run_client import DatabaseWorker -from haven import tiled_client, load_config, exceptions log = logging.getLogger(__name__) @@ -289,7 +285,8 @@ def calculate_ydata( def load_run_data(self, run, x_signal, y_signal, r_signal, use_reference=True): if "" in [x_signal, y_signal] or (use_reference and r_signal == ""): log.debug( - f"Empty signal name requested: x='{x_signal}', y='{y_signal}', r='{r_signal}'" + f"Empty signal name requested: x='{x_signal}', y='{y_signal}'," + f" r='{r_signal}'" ) raise exceptions.EmptySignalName signals = [x_signal, y_signal] diff --git a/src/firefly/run_client.py b/src/firefly/run_client.py index 95cf65dd..227c49fd 100644 --- a/src/firefly/run_client.py +++ b/src/firefly/run_client.py @@ -3,12 +3,11 @@ from collections import OrderedDict from typing import Sequence -from qtpy.QtCore import QObject, Slot, Signal +from qtpy.QtCore import QObject, Signal, Slot from tiled import queries from haven import tiled_client - log = logging.getLogger(__name__) diff --git a/src/firefly/status.py b/src/firefly/status.py index 556f9aaf..27be9b7d 100644 --- a/src/firefly/status.py +++ b/src/firefly/status.py @@ -1,8 +1,6 @@ import logging -import haven - -from firefly import display, FireflyApplication +from firefly import FireflyApplication, display log = logging.getLogger(__name__) diff --git a/src/firefly/status.ui b/src/firefly/status.ui index 21c4985c..de944018 100644 --- a/src/firefly/status.ui +++ b/src/firefly/status.ui @@ -135,7 +135,7 @@ false - oph://monochromator_energy_user_readback + sig://monochromator_energy_user_readback @@ -196,7 +196,7 @@ Fixed offset - oph://monochromator_mode + sig://monochromator_mode @@ -237,7 +237,7 @@ true - oph://front_end_shutter_pss_state + sig://front_end_shutter_pss_state true @@ -285,7 +285,7 @@ false - oph://front_end_shutter_open_signal + sig://front_end_shutter_open_signal 1 @@ -330,7 +330,7 @@ true - oph://hutch_shutter_pss_state + sig://hutch_shutter_pss_state true @@ -366,7 +366,7 @@ Open - oph://hutch_shutter_open_signal + sig://hutch_shutter_open_signal 1 @@ -385,7 +385,7 @@ Close - oph://hutch_shutter_close_signal + sig://hutch_shutter_close_signal 1 @@ -447,7 +447,7 @@ 746328 - oph://bss_proposal_proposal_id + sig://bss_proposal_proposal_id @@ -469,7 +469,7 @@ true - oph://bss_proposal_title + sig://bss_proposal_title PyDMLabel::String @@ -499,7 +499,7 @@ 5564987 - oph://bss_esaf_esaf_id + sig://bss_esaf_esaf_id @@ -521,7 +521,7 @@ true - oph://bss_esaf_title + sig://bss_esaf_title PyDMLabel::String @@ -546,7 +546,7 @@ Franklin, Watson, Crick - oph://bss_esaf_user_last_names + sig://bss_esaf_user_last_names PyDMLabel::String @@ -569,7 +569,7 @@ 1901-01-01 8:00:00 - oph://bss_esaf_end_date + sig://bss_esaf_end_date diff --git a/src/firefly/tests/test_application.py b/src/firefly/tests/test_application.py index a9411692..839f83f8 100644 --- a/src/firefly/tests/test_application.py +++ b/src/firefly/tests/test_application.py @@ -1,15 +1,6 @@ -import time -import pytest from unittest.mock import MagicMock -import asyncio - -from bluesky import RunEngine, plans as bp -from qtpy.QtCore import QThread -from qtpy.QtTest import QSignalSpy -from bluesky_queueserver_api.zmq import REManagerAPI -from firefly.queue_client import QueueClient -from firefly.application import REManagerAPI +import pytest def test_setup(ffapp): diff --git a/src/firefly/tests/test_area_detector_display.py b/src/firefly/tests/test_area_detector_display.py index 50d9c8e8..8fdc4a8d 100644 --- a/src/firefly/tests/test_area_detector_display.py +++ b/src/firefly/tests/test_area_detector_display.py @@ -1,10 +1,10 @@ -import pyqtgraph +from unittest import mock + import numpy as np import pydm -from unittest import mock +import pyqtgraph from firefly.area_detector_viewer import AreaDetectorViewerDisplay -from haven.instrument.camera import load_cameras def test_open_camera_viewer_actions(ffapp, qtbot, sim_camera): diff --git a/src/firefly/tests/test_bss_display.py b/src/firefly/tests/test_bss_display.py index c0ae6a4e..ba2dbeed 100644 --- a/src/firefly/tests/test_bss_display.py +++ b/src/firefly/tests/test_bss_display.py @@ -1,11 +1,9 @@ import pytest -import time -from qtpy.QtGui import QStandardItemModel from qtpy.QtCore import Qt -from epics import caget, caput +from qtpy.QtGui import QStandardItemModel -from haven.instrument.aps import load_aps from firefly.bss import BssDisplay +from haven.instrument.aps import load_aps @pytest.fixture() @@ -13,25 +11,29 @@ def bss_api(mocker): api = mocker.MagicMock() api.getCurrentEsafs.return_value = [ { - "description": "We will perform some K-edge and L-edge XAFS measurements of " - "some transition metal nanoparticle powder samples such as " - "silver, palladium, gold, copper and platinum. \r\n" - "\r\n" - "Some of the measurements will need in situ gas adsorption " - "and/or heating conditions. Standard beamline temperature " - "controller and power supply will be used to heat samples to " - "100C. Some of the samples may be in solution phase. We will " - "also perform Au L2 edge XAFS measurement in HERFD mode of " - "some metal nanoparticle samples. The nanoparticle samples " - "are all unbound nanostructured materials. Samples will be " - "encapsulated in Kapton tape or prepared by using capillaries " - "and quartz wool. For solution phase measurements, the Teflon " - "sample holder will be used.", + "description": ( + "We will perform some K-edge and L-edge XAFS measurements of " + "some transition metal nanoparticle powder samples such as " + "silver, palladium, gold, copper and platinum. \r\n" + "\r\n" + "Some of the measurements will need in situ gas adsorption " + "and/or heating conditions. Standard beamline temperature " + "controller and power supply will be used to heat samples to " + "100C. Some of the samples may be in solution phase. We will " + "also perform Au L2 edge XAFS measurement in HERFD mode of " + "some metal nanoparticle samples. The nanoparticle samples " + "are all unbound nanostructured materials. Samples will be " + "encapsulated in Kapton tape or prepared by using capillaries " + "and quartz wool. For solution phase measurements, the Teflon " + "sample holder will be used." + ), "esafId": 269238, "esafStatus": "Pending", - "esafTitle": "A Partner User Proposal to Continue the Successful " - "Collaboration between the Canadian Light Source Inc. and the " - "Advanced Photon Source", + "esafTitle": ( + "A Partner User Proposal to Continue the Successful " + "Collaboration between the Canadian Light Source Inc. and the " + "Advanced Photon Source" + ), "experimentEndDate": "2023-03-31 08:00:00", "experimentStartDate": "2023-03-28 08:00:00", "experimentUsers": [ @@ -74,7 +76,10 @@ def bss_api(mocker): api.getCurrentProposals.return_value = [ { - "title": "A Partner User Proposal to Continue the Successful Collaboration between the Canadian Light Source Inc. and the Advanced Photon Source", + "title": ( + "A Partner User Proposal to Continue the Successful Collaboration" + " between the Canadian Light Source Inc. and the Advanced Photon Source" + ), "id": 74163, "experimenters": [ { diff --git a/src/firefly/tests/test_cameras_display.py b/src/firefly/tests/test_cameras_display.py index 3289021b..168325e5 100644 --- a/src/firefly/tests/test_cameras_display.py +++ b/src/firefly/tests/test_cameras_display.py @@ -1,14 +1,11 @@ -import pytest import json -import haven -from pydm.data_plugins.epics_plugin import EPICSPlugin +import pytest from pydm.widgets.channel import PyDMChannel -from qtpy import QtWidgets, QtGui, QtCore +from qtpy import QtCore, QtGui, QtWidgets -from firefly.cameras import CamerasDisplay from firefly.camera import CameraDisplay, DetectorStates - +from firefly.cameras import CamerasDisplay macros = {"PREFIX": "camera_ioc:", "DESC": "Camera A"} diff --git a/src/firefly/tests/test_count_window.py b/src/firefly/tests/test_count_window.py index 1887c3d7..491275dd 100644 --- a/src/firefly/tests/test_count_window.py +++ b/src/firefly/tests/test_count_window.py @@ -1,7 +1,7 @@ from unittest import mock -from qtpy import QtCore from bluesky_queueserver_api import BPlan +from qtpy import QtCore from firefly.plans.count import CountDisplay diff --git a/src/firefly/tests/test_energy_display.py b/src/firefly/tests/test_energy_display.py index d67ba188..50b9f3fe 100644 --- a/src/firefly/tests/test_energy_display.py +++ b/src/firefly/tests/test_energy_display.py @@ -1,28 +1,23 @@ -import time from unittest import mock -import pytest -from qtpy import QtWidgets, QtCore -from bluesky_queueserver_api import BPlan from apstools.devices.aps_undulator import ApsUndulator +from bluesky_queueserver_api import BPlan from ophyd.sim import make_fake_device +from qtpy import QtCore import haven -from haven.instrument.monochromator import load_monochromator -from haven.instrument.energy_positioner import load_energy_positioner from firefly.energy import EnergyDisplay - FakeMonochromator = make_fake_device(haven.instrument.monochromator.Monochromator) -FakeEnergyPositioner = make_fake_device(haven.instrument.energy_positioner.EnergyPositioner) +FakeEnergyPositioner = make_fake_device( + haven.instrument.energy_positioner.EnergyPositioner +) FakeUndulator = make_fake_device(ApsUndulator) def test_mono_caqtdm_macros(qtbot, ffapp, sim_registry): # Create fake device - mono = sim_registry.register( - FakeMonochromator("mono_ioc", name="monochromator") - ) + mono = sim_registry.register(FakeMonochromator("mono_ioc", name="monochromator")) sim_registry.register( FakeEnergyPositioner( mono_pv="mono_ioc:Energy", @@ -54,9 +49,7 @@ def test_mono_caqtdm_macros(qtbot, ffapp, sim_registry): def test_id_caqtdm_macros(qtbot, ffapp, sim_registry): # Create fake device - mono = FakeMonochromator( - "mono_ioc", name="monochromator" - ) + mono = FakeMonochromator("mono_ioc", name="monochromator") sim_registry.register( FakeEnergyPositioner( mono_pv="mono_ioc:Energy", @@ -82,9 +75,7 @@ def test_id_caqtdm_macros(qtbot, ffapp, sim_registry): def test_move_energy(qtbot, ffapp, sim_registry): - mono = FakeMonochromator( - "mono_ioc", name="monochromator" - ) + mono = FakeMonochromator("mono_ioc", name="monochromator") sim_registry.register( FakeEnergyPositioner( mono_pv="mono_ioc:Energy", @@ -112,9 +103,7 @@ def check_item(item): def test_predefined_energies(qtbot, ffapp, sim_registry): # Create fake device - mono = FakeMonochromator( - "mono_ioc", name="monochromator" - ) + mono = FakeMonochromator("mono_ioc", name="monochromator") sim_registry.register( FakeEnergyPositioner( mono_pv="mono_ioc:Energy", diff --git a/src/firefly/tests/test_main_window.py b/src/firefly/tests/test_main_window.py index e8c021de..19d54113 100644 --- a/src/firefly/tests/test_main_window.py +++ b/src/firefly/tests/test_main_window.py @@ -1,10 +1,4 @@ -from unittest import mock - -import time -import pytest - from firefly.main_window import FireflyMainWindow, PlanMainWindow -from firefly.application import FireflyApplication def test_navbar(ffapp): diff --git a/src/firefly/tests/test_motor_menu.py b/src/firefly/tests/test_motor_menu.py index 01f72469..8ae220d0 100644 --- a/src/firefly/tests/test_motor_menu.py +++ b/src/firefly/tests/test_motor_menu.py @@ -1,16 +1,8 @@ -import time import pytest -import logging -import asyncio -from unittest import mock - -import epics -from haven.instrument import motor, registry -from qtpy import QtWidgets -from ophyd.sim import instantiate_fake_device, make_fake_device +from ophyd.sim import make_fake_device from firefly.main_window import FireflyMainWindow -from firefly.application import FireflyApplication +from haven.instrument import motor @pytest.fixture diff --git a/src/firefly/tests/test_ophyd_connection.py b/src/firefly/tests/test_ophyd_connection.py index 89234e5c..d6e3210b 100644 --- a/src/firefly/tests/test_ophyd_connection.py +++ b/src/firefly/tests/test_ophyd_connection.py @@ -1,16 +1,16 @@ import time +from unittest.mock import MagicMock + import pytest -from ophyd import EpicsSignal, EpicsMotor, sim -from ophyd.sim import instantiate_fake_device, make_fake_device -from pydm.data_plugins import plugin_for_address, add_plugin +from ophyd.sim import make_fake_device +from pydm import PyDMChannel +from pydm.data_plugins import plugin_for_address from pydm.main_window import PyDMMainWindow from pydm.widgets import PyDMLineEdit -from pydm import PyDMChannel from qtpy import QtCore -from unittest.mock import MagicMock +from typhos.plugins.core import SignalPlugin from haven import HavenMotor -from firefly.ophyd_plugin import Connection as OphydConnection, OphydPlugin class DummyObject(QtCore.QObject): @@ -19,16 +19,18 @@ class DummyObject(QtCore.QObject): @pytest.fixture() def sim_motor(sim_registry): + sim_registry.use_typhos = True FakeMotor = make_fake_device(HavenMotor) motor = FakeMotor("255idVME:m1", name="motor") motor.user_setpoint.sim_set_limits((0, 1000)) sim_registry.register(motor) + return motor @pytest.fixture() def ophyd_channel(sim_motor): - channel = PyDMChannel(address="oph://motor.user_setpoint") + channel = PyDMChannel(address="sig://motor.user_setpoint") return channel @@ -42,100 +44,101 @@ def ophyd_connection(sim_motor, ophyd_channel, pydm_ophyd_plugin): def test_ophyd_pydm_ophyd_plugin(pydm_ophyd_plugin): - plugin = plugin_for_address("oph://sim_detector") - assert isinstance(plugin, OphydPlugin) + plugin = plugin_for_address("sig://sim_detector") + assert isinstance(plugin, SignalPlugin) +@pytest.mark.skip(reason="Moved to typhos, test should be removed in the future") def test_new_value(sim_motor, ophyd_connection, qtbot): - with qtbot.waitSignal(ophyd_connection.new_value_signal) as blocker: + with qtbot.waitSignal(ophyd_connection.new_value_signal, timeout=1000) as blocker: sim_motor.set(45.0) assert blocker.args[0] == 45.0 -def test_set_value(sim_motor, ophyd_connection, ophyd_channel): - ophyd_connection.set_value(87.0).wait() - assert sim_motor.user_setpoint.get(use_monitor=False) == 87.0 +# def test_set_value(sim_motor, ophyd_connection, ophyd_channel): +# ophyd_connection.set_value(87.0).wait() +# assert sim_motor.user_setpoint.get(use_monitor=False) == 87.0 def test_missing_device(sim_motor, pydm_ophyd_plugin, qtbot, ffapp): """See if the connection responds properly if the device is not there.""" connection_slot = MagicMock() channel = PyDMChannel( - address="oph://motor.nonsense_parts", connection_slot=connection_slot + address="sig://motor.nonsense_parts", connection_slot=connection_slot ) pydm_ophyd_plugin.add_connection(channel) -def test_update_ctrl_vals(sim_motor, ophyd_connection, qtbot): - conn = ophyd_connection - conn._ctrl_vars = {} - # Check if the connection state is updated - with qtbot.waitSignal(conn.connection_state_signal) as blocker: - conn.update_ctrl_vars(connected=True) - assert blocker.args[0] is True - # Make sure it isn't emitted a second time if it doesn't change - conn._ctrl_vars = {"connected": True} - conn.connection_state_signal = MagicMock() - conn.update_ctrl_vars(connected=True) - assert not conn.connection_state_signal.emit.called - # Check other metadata signals - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.new_severity_signal) as blocker: - conn.update_ctrl_vars(severity=2) - assert blocker.args[0] == 2 - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.write_access_signal) as blocker: - conn.update_ctrl_vars(write_access=True) - assert blocker.args[0] is True - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.enum_strings_signal) as blocker: - conn.update_ctrl_vars(enum_strs=("Option 1", "Option 2")) - assert blocker.args[0] == ("Option 1", "Option 2") - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.unit_signal) as blocker: - conn.update_ctrl_vars(units="µm") - assert blocker.args[0] == "µm" - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.prec_signal) as blocker: - conn.update_ctrl_vars(precision=5) - assert blocker.args[0] == 5 - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.lower_ctrl_limit_signal) as blocker: - conn.update_ctrl_vars(lower_ctrl_limit=-200) - assert blocker.args[0] == -200 - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.upper_ctrl_limit_signal) as blocker: - conn.update_ctrl_vars(upper_ctrl_limit=850.3) - assert blocker.args[0] == 850.3 - - conn._ctrl_vars = {} - with qtbot.waitSignal(conn.timestamp_signal) as blocker: - conn.update_ctrl_vars(timestamp=1693014035.3913143) - assert blocker.args[0] == 1693014035.3913143 - { - "connected": True, - "read_access": True, - "write_access": True, - "timestamp": 1693014035.3913143, - "status": None, - "severity": None, - "precision": None, - "lower_ctrl_limit": None, - "upper_ctrl_limit": None, - "units": None, - "enum_strs": None, - "setpoint_status": None, - "setpoint_severity": None, - "setpoint_precision": None, - "setpoint_timestamp": None, - "sub_type": "meta", - } +# def test_update_ctrl_vals(sim_motor, ophyd_connection, qtbot): +# conn = ophyd_connection +# conn._ctrl_vars = {} +# # Check if the connection state is updated +# with qtbot.waitSignal(conn.connection_state_signal) as blocker: +# conn.update_ctrl_vars(connected=True) +# assert blocker.args[0] is True +# # Make sure it isn't emitted a second time if it doesn't change +# conn._ctrl_vars = {"connected": True} +# conn.connection_state_signal = MagicMock() +# conn.update_ctrl_vars(connected=True) +# assert not conn.connection_state_signal.emit.called +# # Check other metadata signals +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.new_severity_signal) as blocker: +# conn.update_ctrl_vars(severity=2) +# assert blocker.args[0] == 2 + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.write_access_signal) as blocker: +# conn.update_ctrl_vars(write_access=True) +# assert blocker.args[0] is True + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.enum_strings_signal) as blocker: +# conn.update_ctrl_vars(enum_strs=("Option 1", "Option 2")) +# assert blocker.args[0] == ("Option 1", "Option 2") + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.unit_signal) as blocker: +# conn.update_ctrl_vars(units="µm") +# assert blocker.args[0] == "µm" + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.prec_signal) as blocker: +# conn.update_ctrl_vars(precision=5) +# assert blocker.args[0] == 5 + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.lower_ctrl_limit_signal) as blocker: +# conn.update_ctrl_vars(lower_ctrl_limit=-200) +# assert blocker.args[0] == -200 + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.upper_ctrl_limit_signal) as blocker: +# conn.update_ctrl_vars(upper_ctrl_limit=850.3) +# assert blocker.args[0] == 850.3 + +# conn._ctrl_vars = {} +# with qtbot.waitSignal(conn.timestamp_signal) as blocker: +# conn.update_ctrl_vars(timestamp=1693014035.3913143) +# assert blocker.args[0] == 1693014035.3913143 +# { +# "connected": True, +# "read_access": True, +# "write_access": True, +# "timestamp": 1693014035.3913143, +# "status": None, +# "severity": None, +# "precision": None, +# "lower_ctrl_limit": None, +# "upper_ctrl_limit": None, +# "units": None, +# "enum_strs": None, +# "setpoint_status": None, +# "setpoint_severity": None, +# "setpoint_precision": None, +# "setpoint_timestamp": None, +# "sub_type": "meta", +# } def test_widget_signals(sim_motor, ffapp, qtbot): @@ -143,8 +146,7 @@ def test_widget_signals(sim_motor, ffapp, qtbot): sim_motor.user_setpoint.set(5.15) sim_motor.user_setpoint._metadata["precision"] = 3 window = PyDMMainWindow() - widget = PyDMLineEdit(parent=window, init_channel="oph://motor.user_setpoint") - # widget.precisionChanged(3) + widget = PyDMLineEdit(parent=window, init_channel="sig://motor.user_setpoint") ffapp.processEvents() time.sleep(0.05) assert widget.text() == "5.150" diff --git a/src/firefly/tests/test_queue_client.py b/src/firefly/tests/test_queue_client.py index 70f54126..82597035 100644 --- a/src/firefly/tests/test_queue_client.py +++ b/src/firefly/tests/test_queue_client.py @@ -1,20 +1,11 @@ -import time -import pytest from unittest.mock import MagicMock -import asyncio -from collections import ChainMap -from bluesky import RunEngine, plans as bp -from qtpy.QtCore import QThread -from qtpy.QtTest import QSignalSpy -from qtpy.QtWidgets import QAction +import pytest from bluesky_queueserver_api import BPlan -from bluesky_queueserver_api.zmq import REManagerAPI from pytestqt.exceptions import TimeoutError +from qtpy.QtWidgets import QAction from firefly.queue_client import QueueClient -from firefly.application import REManagerAPI - qs_status = { "msg": "RE Manager v0.0.18", @@ -222,7 +213,9 @@ def client(): api = MagicMock() api.queue_start.return_value = {"success": True} api.status.return_value = qs_status - api.queue_start.return_value = {"success": True,} + api.queue_start.return_value = { + "success": True, + } api.devices_allowed.return_value = {"success": True, "devices_allowed": {}} api.environment_open.return_value = {"success": True} api.environment_close.return_value = {"success": True} @@ -231,7 +224,11 @@ def client(): autoplay_action.setCheckable(True) open_environment_action = QAction() open_environment_action.setCheckable(True) - client = QueueClient(api=api, autoplay_action=autoplay_action, open_environment_action=open_environment_action) + client = QueueClient( + api=api, + autoplay_action=autoplay_action, + open_environment_action=open_environment_action, + ) yield client @@ -339,7 +336,7 @@ def test_open_environment(client, qtbot): def test_devices_available(client, qtbot): """Check that the queue client provides a list of devices that can be used in plans. - + """ api = client.api api.devices_allowed.return_value = devices_allowed diff --git a/src/firefly/tests/test_run_browser.py b/src/firefly/tests/test_run_browser.py index 4e43cdb0..48108bbc 100644 --- a/src/firefly/tests/test_run_browser.py +++ b/src/firefly/tests/test_run_browser.py @@ -1,25 +1,19 @@ -import time -from unittest.mock import MagicMock -from collections import namedtuple import logging -import pytest +from unittest.mock import MagicMock -from qtpy.QtCore import Qt -from pyqtgraph import PlotItem, PlotWidget import numpy as np import pandas as pd +import pytest +from pyqtgraph import PlotItem, PlotWidget +from qtpy.QtCore import Qt from tiled.adapters.mapping import MapAdapter -from tiled.adapters.array import ArrayAdapter from tiled.adapters.xarray import DatasetAdapter -from tiled.server.app import build_app from tiled.client import Context, from_context +from tiled.server.app import build_app -from haven import tiled_client -from firefly.main_window import PlanMainWindow from firefly.run_browser import RunBrowserDisplay from firefly.run_client import DatabaseWorker - log = logging.getLogger(__name__) @@ -28,6 +22,7 @@ def wait_for_runs_model(display, qtbot): pass +# Some mocked test data run1 = pd.DataFrame( { "energy_energy": np.linspace(8300, 8400, num=100), @@ -92,11 +87,7 @@ def client(): with Context.from_app(app) as context: client = from_context(context) yield client["255id_testing"] - -def test_client_fixture(client): - """Does the client fixture load without stalling the test runner?""" - pass @pytest.fixture() def display(ffapp, client, qtbot): @@ -107,6 +98,11 @@ def display(ffapp, client, qtbot): finally: display._thread.quit() display._thread.wait(msecs=5000) + assert not display._thread.isRunning() + + +def test_client_fixture(client): + """Does the client fixture load without stalling the test runner?""" def test_run_viewer_action(ffapp, monkeypatch): diff --git a/src/firefly/tests/test_tiled_server.py b/src/firefly/tests/test_tiled_server.py index 12a0d8cb..50f21180 100644 --- a/src/firefly/tests/test_tiled_server.py +++ b/src/firefly/tests/test_tiled_server.py @@ -1,14 +1,11 @@ """Tests to check that the simulated tiled client works properly.""" -import pytest - import numpy -from tiled.adapters.mapping import MapAdapter +import pytest from tiled.adapters.array import ArrayAdapter -from tiled.adapters.xarray import DatasetAdapter -from tiled.server.app import build_app +from tiled.adapters.mapping import MapAdapter from tiled.client import Context, from_context - +from tiled.server.app import build_app simple_tree = MapAdapter( { @@ -35,4 +32,3 @@ def client(): def test_client_fixture(client): """Does the client fixture load without stalling the test runner?""" - pass diff --git a/src/firefly/tests/test_voltmeters.py b/src/firefly/tests/test_voltmeters.py index 272ef07a..3763d044 100644 --- a/src/firefly/tests/test_voltmeters.py +++ b/src/firefly/tests/test_voltmeters.py @@ -1,13 +1,7 @@ -import time - -from unittest import mock import pytest -from qtpy import QtWidgets import haven - from firefly.main_window import FireflyMainWindow -from firefly.application import FireflyApplication from firefly.voltmeter import VoltmeterDisplay from firefly.voltmeters import VoltmetersDisplay @@ -70,8 +64,8 @@ def test_ion_chamber_menu(fake_ion_chambers, qtbot, ffapp): # Create the window window = FireflyMainWindow() # Check that the menu items have been created - assert hasattr(window.ui, "menuDetectors") - assert hasattr(window.ui, "menuIonChambers") + assert hasattr(window.ui, "detectors_menu") + assert hasattr(window.ui, "ion_chambers_menu") assert len(ffapp.ion_chamber_actions) == 2 diff --git a/src/firefly/tests/test_xafs_scan.py b/src/firefly/tests/test_xafs_scan.py index 8ea85762..95df5cb7 100644 --- a/src/firefly/tests/test_xafs_scan.py +++ b/src/firefly/tests/test_xafs_scan.py @@ -1,5 +1,3 @@ -import pytest - from firefly.xafs_scan import XafsScanDisplay diff --git a/src/firefly/tests/test_xrf_detector_display.py b/src/firefly/tests/test_xrf_detector_display.py index 2f41f2b6..aee745ed 100644 --- a/src/firefly/tests/test_xrf_detector_display.py +++ b/src/firefly/tests/test_xrf_detector_display.py @@ -1,14 +1,13 @@ -import time -from ophyd import Kind - import numpy as np -from pyqtgraph import PlotItem import pytest +from pyqtgraph import PlotItem from qtpy import QtCore -from firefly.xrf_detector import XRFDetectorDisplay, XRFPlotWidget +from firefly.xrf_detector import XRFDetectorDisplay from firefly.xrf_roi import XRFROIDisplay +detectors = ["dxp", "xspress"] + @pytest.fixture() def xrf_display(ffapp, request): @@ -29,10 +28,10 @@ def xrf_display(ffapp, request): plot_widget.update_spectrum(1, spectra[1]) plot_widget.update_spectrum(2, spectra[2]) plot_widget.update_spectrum(3, spectra[3]) - return display + yield display -@pytest.mark.parametrize("det_fixture", ["dxp", "xspress"]) +@pytest.mark.parametrize("det_fixture", detectors) def test_open_xrf_detector_viewer_actions(ffapp, qtbot, det_fixture, request): sim_det = request.getfixturevalue(det_fixture) # Get the area detector parts ready @@ -44,7 +43,7 @@ def test_open_xrf_detector_viewer_actions(ffapp, qtbot, det_fixture, request): assert "FireflyMainWindow_xrf_detector_vortex_me4" in ffapp.windows.keys() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_roi_widgets(xrf_display): xrf_display.draw_roi_widgets(2) # Check that the widgets were drawn @@ -52,7 +51,7 @@ def test_roi_widgets(xrf_display): disp = xrf_display.roi_displays[0] -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_roi_element_comboboxes(ffapp, qtbot, xrf_display): # Check that the comboboxes have the right number of entries element_cb = xrf_display.ui.mca_combobox @@ -61,7 +60,7 @@ def test_roi_element_comboboxes(ffapp, qtbot, xrf_display): assert roi_cb.count() == xrf_display.device.num_rois -@pytest.mark.parametrize("det_fixture", ["dxp", "xspress"]) +@pytest.mark.parametrize("det_fixture", detectors) def test_roi_selection(ffapp, qtbot, det_fixture, request): det = request.getfixturevalue(det_fixture) display = XRFROIDisplay(macros={"DEV": det.name, "NUM": 2, "MCA": 2, "ROI": 2}) @@ -78,7 +77,7 @@ def test_roi_selection(ffapp, qtbot, det_fixture, request): assert f"background: {display.selected_background}" not in display.styleSheet() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_all_rois_selection(xrf_display): """Are all the other ROIs disabled when one is selected?""" roi_display = xrf_display.roi_displays[0] @@ -88,7 +87,7 @@ def test_all_rois_selection(xrf_display): assert not xrf_display.roi_displays[1].isEnabled() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_all_mcas_selection(xrf_display): """Are all the other ROIs disabled when one is selected?""" mca_display = xrf_display.mca_displays[0] @@ -98,7 +97,7 @@ def test_all_mcas_selection(xrf_display): assert not xrf_display.mca_displays[1].isEnabled() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_update_roi_spectra(qtbot, xrf_display): spectra = np.random.default_rng(seed=0).integers( 0, 65536, dtype=np.int_, size=(4, 1024) @@ -123,7 +122,7 @@ def test_update_roi_spectra(qtbot, xrf_display): assert len(data_items) == 1 -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_update_mca_spectra(xrf_display, qtbot): spectra = np.random.default_rng(seed=0).integers( 0, 65536, dtype=np.int_, size=(4, 1024) @@ -151,7 +150,7 @@ def test_update_mca_spectra(xrf_display, qtbot): assert len(data_items) == 2 -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_mca_selected_highlights(qtbot, xrf_display): """Is the spectrum highlighted when the element row is selected.""" mca_display = xrf_display.mca_displays[1] @@ -177,7 +176,7 @@ def test_mca_selected_highlights(qtbot, xrf_display): assert other_data_item.opacity() == 0.15 -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_show_mca_region_visibility(xrf_display): """Is the spectrum highlighted when the element row is selected.""" # Check that the region is hidden at startup @@ -193,7 +192,7 @@ def test_show_mca_region_visibility(xrf_display): assert not region.isVisible() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_show_roi_region(xrf_display): """Is the spectrum highlighted when the element row is selected.""" # Check that the region is hidden at startup @@ -214,7 +213,7 @@ def test_show_roi_region(xrf_display): assert selected_region.isVisible() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_mca_region_channels(xrf_display): """Are the channel access connections between the ROI selection region and the hi/lo channel PVs correct? @@ -225,7 +224,7 @@ def test_mca_region_channels(xrf_display): mca_display = xrf_display.mca_displays[1] mca_display._embedded_widget = mca_display.open_file(force=True) xrf_display.mca_selected(is_selected=True, mca_num=2) - correct_address = "oph://vortex_me4.mcas.mca2.rois.roi0.hi_chan" + correct_address = "sig://vortex_me4.mcas.mca2.rois.roi0.hi_chan" region = plot_widget.region(mca_num=2, roi_num=0) assert region.hi_channel.address == correct_address region.hi_channel.value_slot(108) @@ -234,7 +233,7 @@ def test_mca_region_channels(xrf_display): assert region.getRegion()[0] == 47 -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_mca_copyall_button(xrf_display, qtbot): xrf_display.mca_selected(is_selected=True, mca_num=1) assert xrf_display.ui.mca_copyall_button.isEnabled() @@ -256,7 +255,7 @@ def test_mca_copyall_button(xrf_display, qtbot): assert not xrf_display.ui.mca_copyall_button.isEnabled() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_roi_copyall_button(xrf_display, qtbot): # Set up ROI rows embedded display widgets for disp in xrf_display.roi_displays: @@ -282,7 +281,7 @@ def test_roi_copyall_button(xrf_display, qtbot): assert not xrf_display.ui.roi_copyall_button.isEnabled() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_mca_enableall_checkbox(xrf_display): checkbox = xrf_display.ui.mca_enableall_checkbox assert checkbox.checkState() == QtCore.Qt.PartiallyChecked @@ -301,7 +300,7 @@ def test_mca_enableall_checkbox(xrf_display): assert not display.embedded_widget.ui.enabled_checkbox.isChecked() -@pytest.mark.parametrize("xrf_display", ["dxp", "xspress"], indirect=True) +@pytest.mark.parametrize("xrf_display", detectors, indirect=True) def test_roi_enableall_checkbox(xrf_display): checkbox = xrf_display.ui.roi_enableall_checkbox assert checkbox.checkState() == QtCore.Qt.PartiallyChecked diff --git a/src/firefly/voltmeter.py b/src/firefly/voltmeter.py index 6d898316..c9104e92 100644 --- a/src/firefly/voltmeter.py +++ b/src/firefly/voltmeter.py @@ -1,12 +1,11 @@ import logging -from typing import Sequence, Mapping, Optional +from typing import Mapping, Optional, Sequence -from pydm.widgets.channel import PyDMChannel -from haven.instrument.ion_chamber import IonChamber -from haven import load_config, exceptions, registry import qtawesome as qta -from firefly import display, FireflyApplication +from firefly import FireflyApplication, display +from haven import exceptions, registry +from haven.instrument.ion_chamber import IonChamber log = logging.getLogger(__name__) diff --git a/src/firefly/voltmeter.ui b/src/firefly/voltmeter.ui index 7f4b3dc3..bbf16260 100644 --- a/src/firefly/voltmeter.ui +++ b/src/firefly/voltmeter.ui @@ -63,7 +63,7 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - oph://${IC}.description + sig://${IC}.description PyDMLabel::String @@ -93,7 +93,7 @@ The measured voltage output from the pre-amp. - oph://${IC}.voltmeter.volts + sig://${IC}.voltmeter.volts false @@ -212,7 +212,7 @@ The measured voltage output from the pre-amp. - oph://${IC}.voltmeter.volts + sig://${IC}.voltmeter.volts false @@ -290,7 +290,7 @@ The calculated current based on the voltage from the voltmeter and the pre-amp settings. - oph://${IC}.voltmeter.amps + sig://${IC}.voltmeter.amps PyDMLabel::Exponential @@ -427,13 +427,13 @@ - [{"name": "Gain button lower range", "property": "Enable", "initial_value": "True", "expression": "ch[0] < 27", "channels": [{"channel": "oph://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": "If the sensitivity is at its highest setting, disable the button so users don't click it unnecessarily."}] + [{"name": "Gain button lower range", "property": "Enable", "initial_value": "True", "expression": "ch[0] < 27", "channels": [{"channel": "sig://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": "If the sensitivity is at its highest setting, disable the button so users don't click it unnecessarily."}] Decrease the pre-amp gain (higher sensitivity values) - oph://${IC}.preamp.sensitivity_level + sig://${IC}.preamp.sensitivity_level Are you sure you want to proceed? @@ -473,7 +473,7 @@ - [{"name": "Gain button upper range", "property": "Enable", "initial_value": "True", "expression": "ch[0] > 0", "channels": [{"channel": "oph://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": ""}] + [{"name": "Gain button upper range", "property": "Enable", "initial_value": "True", "expression": "ch[0] > 0", "channels": [{"channel": "sig://${IC}.preamp.sensitivity_level", "trigger": true, "use_enum": false}], "notes": ""}] false @@ -488,7 +488,7 @@ false - oph://${IC}.preamp.sensitivity_level + sig://${IC}.preamp.sensitivity_level false @@ -570,7 +570,7 @@ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - oph://${IC}.preamp.sensitivity_text + sig://${IC}.preamp.sensitivity_text PyDMLabel::String diff --git a/src/firefly/voltmeters.py b/src/firefly/voltmeters.py index 103ec266..76c46cf9 100644 --- a/src/firefly/voltmeters.py +++ b/src/firefly/voltmeters.py @@ -1,13 +1,12 @@ import json -import warnings import logging -from typing import Optional, Mapping, Sequence +from typing import Mapping, Optional, Sequence +import qtawesome as qta from pydm.widgets import PyDMEmbeddedDisplay from qtpy import QtWidgets -import haven -import qtawesome as qta +import haven from firefly import display # from .voltmeter import VoltmeterDisplay diff --git a/src/firefly/xrf_detector.py b/src/firefly/xrf_detector.py index 14973719..fedfe43c 100644 --- a/src/firefly/xrf_detector.py +++ b/src/firefly/xrf_detector.py @@ -1,30 +1,25 @@ -import time -import logging -import subprocess -from pathlib import Path -from typing import Sequence, Optional import json -from contextlib import contextmanager -from functools import partial +import logging +import sys from collections import defaultdict -import gc +from contextlib import contextmanager from enum import IntEnum +from functools import partial +from pathlib import Path +from typing import Sequence -from qtpy import uic -from qtpy.QtCore import Qt, Signal, QObject, QThread -from qtpy.QtWidgets import QWidget -import qtawesome as qta -import pyqtgraph -import pydm -from pydm.widgets import PyDMEmbeddedDisplay, PyDMChannel import numpy as np -import matplotlib.pyplot as plt +import pydm +import pyqtgraph +import qtawesome as qta from matplotlib.colors import TABLEAU_COLORS +from pydm.widgets import PyDMChannel, PyDMEmbeddedDisplay +from qtpy import uic +from qtpy.QtCore import Qt, Signal +from qtpy.QtWidgets import QWidget import haven -from firefly import display, FireflyApplication - -import sys +from firefly import FireflyApplication, display np.set_printoptions(threshold=sys.maxsize) @@ -98,7 +93,7 @@ def set_region_lower(self, new_lower): if new_lower == self._last_lower: return log.debug( - "Setting new region lower bound: " f"{new_lower} from {self._last_lower}" + f"Setting new region lower bound: {new_lower} from {self._last_lower}" ) self._last_lower = new_lower self.blockLineSignal = True @@ -110,7 +105,7 @@ def set_region_upper(self, new_upper): if new_upper == self._last_upper: return log.debug( - "Setting new region upper bound: " f"{new_upper} from {self._last_upper}" + f"Setting new region upper bound: {new_upper} from {self._last_upper}" ) self._last_upper = new_upper self.blockLineSignal = True @@ -172,7 +167,7 @@ def region(self, mca_num, roi_num): plot_item = self.ui.plot_widget.getPlotItem() # Create a new region item if necessary if key not in self._region_items.keys(): - address = f"oph://{self.device_name}.mcas.mca{mca_num}.rois.roi{roi_num}" + address = f"sig://{self.device_name}.mcas.mca{mca_num}.rois.roi{roi_num}" color = self.region_color(mca_num=mca_num, roi_num=roi_num) region = ROIRegion( address=address, @@ -266,7 +261,8 @@ def highlight_spectrum(self, mca_num, roi_num, hovered): elif self._selected_spectrum is not None: # Highlight the spectrum that was previously selected log.debug( - f"Reverting to previously selected spectrum: {self._selected_spectrum}" + "Reverting to previously selected spectrum:" + f" {self._selected_spectrum}" ) is_dimmed = key != self._selected_spectrum if is_dimmed: @@ -361,18 +357,18 @@ def leaveEvent(self, event=None): # # Set up a channel for starting detector acquisition # device = self.device # self.start_channel = PyDMChannel( -# address=f"oph://{device.name}.acquire", +# address=f"sig://{device.name}.acquire", # value_signal=self.start_all, # ) # self.start_channel.connect() # self.start_erase_channel = PyDMChannel( -# address=f"oph://{device.name}.acquire", +# address=f"sig://{device.name}.acquire", # value_signal=self.start_erase, # ) # self.start_erase_channel.connect() # # This one gets (dis)connected in response to the continuous button # self.acquiring_channel = PyDMChannel( -# address=f"oph://{device.name}.acquiring", +# address=f"sig://{device.name}.acquiring", # value_slot=self.trigger_next, # ) @@ -567,7 +563,7 @@ def customize_device(self): # Set up data channels self._spectrum_channels = [] for mca_num in range(self.device.num_elements): - address = f"oph://{device.name}.mcas.mca{mca_num}.spectrum" + address = f"sig://{device.name}.mcas.mca{mca_num}.spectrum" channel = pydm.PyDMChannel( address=address, value_slot=partial(self.handle_new_spectrum, mca_num=mca_num), diff --git a/src/firefly/xrf_detector.ui b/src/firefly/xrf_detector.ui index d72b33f8..59e1b62e 100644 --- a/src/firefly/xrf_detector.ui +++ b/src/firefly/xrf_detector.ui @@ -99,7 +99,7 @@ true - oph://${DEV}.dwell_time + sig://${DEV}.dwell_time @@ -114,7 +114,7 @@ Continuous - oph://${DEV}.acquire_multiple + sig://${DEV}.acquire_multiple @@ -127,7 +127,7 @@ Acquire - oph://${DEV}.acquire_single + sig://${DEV}.acquire_single 1 @@ -197,7 +197,7 @@ true - oph://${DEV}.acquire + sig://${DEV}.acquire @@ -231,7 +231,7 @@ Qt::TextSelectableByMouse - oph://${DEV}.cam.array_counter + sig://${DEV}.cam.array_counter @@ -304,7 +304,7 @@ N/A - oph://${DEV}.total_count + sig://${DEV}.total_count @@ -363,7 +363,7 @@ false - oph://${DEV}.dead_time_average + sig://${DEV}.dead_time_average PyDMLabel::Decimal @@ -434,7 +434,7 @@ 14.0 - oph://${DEV}.dead_time_min + sig://${DEV}.dead_time_min Lowest dead time across all elements. @@ -489,7 +489,7 @@ 24.0 - oph://${DEV}.dead_time_max + sig://${DEV}.dead_time_max Highest dead time across all elements. diff --git a/src/firefly/xrf_roi.py b/src/firefly/xrf_roi.py index 69621027..8fa808f7 100644 --- a/src/firefly/xrf_roi.py +++ b/src/firefly/xrf_roi.py @@ -1,5 +1,4 @@ import qtawesome as qta -from pydm import PyDMChannel from qtpy.QtCore import Signal from firefly import display diff --git a/src/firefly/xrf_roi.ui b/src/firefly/xrf_roi.ui index 94987524..c71959f8 100644 --- a/src/firefly/xrf_roi.ui +++ b/src/firefly/xrf_roi.ui @@ -90,7 +90,7 @@ - oph://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.use + sig://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.use Enable or disable this ROI. @@ -152,7 +152,7 @@ Data will be saved either way, but disabled channels will not appear in the list ROI Name - oph://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.label + sig://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.label PyDMLineEdit::String @@ -176,7 +176,7 @@ Data will be saved either way, but disabled channels will not appear in the list Lower bound - oph://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.lo_chan + sig://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.lo_chan PyDMLineEdit::Decimal @@ -203,7 +203,7 @@ Data will be saved either way, but disabled channels will not appear in the list Upper bound - oph://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.hi_chan + sig://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.hi_chan PyDMLineEdit::Decimal @@ -233,7 +233,7 @@ Data will be saved either way, but disabled channels will not appear in the list 34 - oph://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.size + sig://${DEV}.mcas.mca${MCA}.rois.roi${ROI}.size The size of the ROI, in number of channels. diff --git a/src/haven/__init__.py b/src/haven/__init__.py index 7ea95c2d..be245e09 100644 --- a/src/haven/__init__.py +++ b/src/haven/__init__.py @@ -2,50 +2,49 @@ __version__ = "0.1.0" +from ._iconfig import load_config # noqa: F401 + # Top-level imports -from .catalog import load_catalog, load_result, load_data, tiled_client # noqa: F401 +from .catalog import load_catalog, load_data, load_result, tiled_client # noqa: F401 +from .constants import edge_energy # noqa: F401 from .energy_ranges import ERange, KRange, merge_ranges # noqa: F401 -from .plans.energy_scan import energy_scan # noqa: F401 +from .instrument import ( # noqa: F401 + InstrumentRegistry, + IonChamber, + Monochromator, + ion_chamber, + registry, +) +from .instrument.dxp import load_dxp # noqa: F401 +from .instrument.load_instrument import load_instrument # noqa: F401 +from .instrument.motor import HavenMotor # noqa: F401 +from .instrument.xspress import load_xspress # noqa: F401 +from .motor_position import ( # noqa: F401 + get_motor_position, + list_current_motor_positions, + list_motor_positions, + recall_motor_position, + save_motor_position, +) +from .plans.align_motor import align_motor, align_pitch2 # noqa: F401 from .plans.align_slits import align_slits # noqa: F401 -from .plans.beam_properties import knife_scan, fit_step # noqa: F401 -from .plans.xafs_scan import xafs_scan # noqa: F401 +from .plans.auto_gain import AutoGainCallback, auto_gain # noqa:F401 +from .plans.beam_properties import fit_step # noqa: F401 from .plans.beam_properties import knife_scan # noqa: F401 -from .plans.auto_gain import auto_gain, AutoGainCallback # noqa:F401 +from .plans.energy_scan import energy_scan # noqa: F401 +from .plans.fly import fly_scan, grid_fly_scan # noqa: F401 from .plans.mono_gap_calibration import calibrate_mono_gap # noqa: F401 from .plans.mono_ID_calibration import mono_ID_calibration # noqa: F401 -from .plans.set_energy import set_energy # noqa: F401 -from .plans.align_motor import align_motor, align_pitch2 # noqa: F401 -from .plans.shutters import open_shutters, close_shutters # noqa: F401 from .plans.record_dark_current import record_dark_current # noqa: F401 -from .plans.fly import fly_scan, grid_fly_scan # noqa: F401 -from .run_engine import run_engine # noqa: F401 -from ._iconfig import load_config # noqa: F401 -from .preprocessors import ( +from .plans.set_energy import set_energy # noqa: F401 +from .plans.shutters import close_shutters, open_shutters # noqa: F401 +from .plans.xafs_scan import xafs_scan # noqa: F401 +from .preprocessors import ( # noqa: F401 baseline_decorator, baseline_wrapper, - shutter_suspend_wrapper, shutter_suspend_decorator, -) # noqa: F401 -from .constants import edge_energy - -from .motor_position import ( # noqa: F401 - save_motor_position, - list_motor_positions, - get_motor_position, - recall_motor_position, - list_current_motor_positions, -) -from .instrument import ( # noqa: F401 - ion_chamber, - IonChamber, - InstrumentRegistry, - registry, - Monochromator, + shutter_suspend_wrapper, ) -from .instrument.load_instrument import load_instrument # noqa: F401 -from .instrument.motor import HavenMotor # noqa: F401 -from .instrument.dxp import load_dxp # noqa: F401 -from .instrument.xspress import load_xspress # noqa: F401 - -from .xdi_writer import XDIWriter # noqa: F401 from .progress_bar import ProgressBar # noqa: F401 +from .run_engine import run_engine # noqa: F401 +from .xdi_writer import XDIWriter # noqa: F401 diff --git a/src/haven/_iconfig.py b/src/haven/_iconfig.py index b52d249a..ec5fa75c 100644 --- a/src/haven/_iconfig.py +++ b/src/haven/_iconfig.py @@ -9,17 +9,16 @@ "load_config", ] -import os +import argparse import logging -from typing import Sequence +import os import pathlib -import argparse -from functools import lru_cache from contextlib import contextmanager from copy import deepcopy +from typing import Sequence -from mergedeep import merge import tomli +from mergedeep import merge log = logging.getLogger(__name__) diff --git a/src/haven/energy_ranges.py b/src/haven/energy_ranges.py index dda7701b..cbf4bd4a 100644 --- a/src/haven/energy_ranges.py +++ b/src/haven/energy_ranges.py @@ -4,7 +4,6 @@ import pint from scipy import constants - __all__ = ["ERange", "KRange"] diff --git a/src/haven/exceptions.py b/src/haven/exceptions.py index cc18cf6f..e53b324c 100644 --- a/src/haven/exceptions.py +++ b/src/haven/exceptions.py @@ -1,7 +1,7 @@ -from .instrument.instrument_registry import ( +from ophydregistry.exceptions import ( # noqa: F401 ComponentNotFound, - MultipleComponentsFound, InvalidComponentLabel, + MultipleComponentsFound, ) diff --git a/src/haven/instrument/__init__.py b/src/haven/instrument/__init__.py index dd4eebd1..bab75b36 100644 --- a/src/haven/instrument/__init__.py +++ b/src/haven/instrument/__init__.py @@ -1,4 +1,4 @@ +from .instrument_registry import InstrumentRegistry, registry # noqa: F401 from .ion_chamber import IonChamber # noqa: F401 -from .motor import HavenMotor # noqa: F401 from .monochromator import Monochromator # noqa: F401 -from .instrument_registry import InstrumentRegistry, registry # noqa: F401 +from .motor import HavenMotor # noqa: F401 diff --git a/src/haven/instrument/aerotech.py b/src/haven/instrument/aerotech.py index 47dc4de3..9fda4bb2 100644 --- a/src/haven/instrument/aerotech.py +++ b/src/haven/instrument/aerotech.py @@ -1,35 +1,25 @@ -import threading -import time -import logging import asyncio +import logging import math -from typing import Generator, Dict -from datetime import datetime, timedelta +import threading +import time from collections import OrderedDict +from typing import Dict, Generator -from ophyd import ( - Device, - FormattedComponent as FCpt, - EpicsMotor, - Component as Cpt, - Signal, - SignalRO, - Kind, - EpicsSignal, - flyers, -) -from ophyd.status import SubscriptionStatus, AndStatus, StatusBase -from apstools.synApps.asyn import AsynRecord -import pint import numpy as np +import pint +from apstools.synApps.asyn import AsynRecord +from ophyd import Component as Cpt +from ophyd import EpicsMotor, EpicsSignal +from ophyd import FormattedComponent as FCpt +from ophyd import Kind, Signal, flyers +from ophyd.status import SubscriptionStatus -from .delay import DG645Delay -from .stage import XYStage -from .instrument_registry import registry from .._iconfig import load_config from ..exceptions import InvalidScanParameters -from .device import await_for_connection, aload_devices, make_device - +from .delay import DG645Delay +from .device import aload_devices, make_device +from .stage import XYStage log = logging.getLogger(__name__) @@ -400,12 +390,14 @@ def _update_fly_params(self, *args, **kwargs): return if encoder_resolution == 0: log.warning( - f"{self} encoder resolution is zero. Could not update fly scan parameters." + f"{self} encoder resolution is zero. Could not update fly scan" + " parameters." ) return if accel_time <= 0: log.warning( - f"{self} acceleration is non-positive. Could not update fly scan parameters." + f"{self} acceleration is non-positive. Could not update fly scan" + " parameters." ) return # Determine the desired direction of travel and overal sense @@ -506,7 +498,8 @@ def check_flyscan_bounds(self): taxi_distance = abs(taxi.get() - pso.get()) if taxi_distance > (1.1 * step_size): raise InvalidScanParameters( - f"Scan parameters for {taxi}, {pso}, {self.step_size} would produce extra pulses without a window." + f"Scan parameters for {taxi}, {pso}, {self.step_size} would produce" + " extra pulses without a window." ) def enable_pso(self): @@ -610,4 +603,3 @@ def load_aerotech_stage_coros(config=None): def load_aerotech_stages(config=None): """Load the XY stages defined in the config ``[stage]`` section.""" asyncio.run(aload_devices(*load_aerotech_stage_coros(config=config))) - diff --git a/src/haven/instrument/aps.py b/src/haven/instrument/aps.py index 29f6f6a2..f71fd9a6 100644 --- a/src/haven/instrument/aps.py +++ b/src/haven/instrument/aps.py @@ -1,15 +1,12 @@ -import logging -import warnings import asyncio +import logging -from apstools.devices.aps_machine import ApsMachineParametersDevice from apsbss.apsbss_ophyd import EpicsBssDevice +from apstools.devices.aps_machine import ApsMachineParametersDevice -from haven import registry from .._iconfig import load_config from .device import aload_devices, make_device - log = logging.getLogger(__name__) diff --git a/src/haven/instrument/area_detector.py b/src/haven/instrument/area_detector.py index ee7dc779..57ea4166 100644 --- a/src/haven/instrument/area_detector.py +++ b/src/haven/instrument/area_detector.py @@ -1,41 +1,38 @@ -import logging import asyncio +import logging from enum import IntEnum from apstools.devices import CamMixin_V34, SingleTrigger_V34 +from ophyd import ADComponent as ADCpt +from ophyd import DetectorBase as OphydDetectorBase from ophyd import ( - ADComponent as ADCpt, - DetectorBase as OphydDetectorBase, - SimDetectorCam, - Lambda750kCam, EigerDetectorCam, - SingleTrigger, Kind, + Lambda750kCam, OphydObject, + SimDetectorCam, + SingleTrigger, ) from ophyd.areadetector.base import EpicsSignalWithRBV as SignalWithRBV from ophyd.areadetector.filestore_mixins import FileStoreHDF5IterativeWrite from ophyd.areadetector.plugins import ( - HDF5Plugin_V34, HDF5Plugin_V31, - ImagePlugin_V34, + HDF5Plugin_V34, ImagePlugin_V31, - PvaPlugin_V34, + ImagePlugin_V34, + OverlayPlugin, PvaPlugin_V31, - TIFFPlugin_V34, - TIFFPlugin_V31, - ROIPlugin_V34, + PvaPlugin_V34, ROIPlugin_V31, - StatsPlugin_V31 as OphydStatsPlugin_V31, - StatsPlugin_V34 as OphydStatsPlugin_V34, - OverlayPlugin, + ROIPlugin_V34, ) +from ophyd.areadetector.plugins import StatsPlugin_V31 as OphydStatsPlugin_V31 +from ophyd.areadetector.plugins import StatsPlugin_V34 as OphydStatsPlugin_V34 +from ophyd.areadetector.plugins import TIFFPlugin_V31 -from .._iconfig import load_config -from .instrument_registry import registry -from .device import make_device from .. import exceptions -from .device import await_for_connection, aload_devices +from .._iconfig import load_config +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/camera.py b/src/haven/instrument/camera.py index 06d3be92..219dac63 100644 --- a/src/haven/instrument/camera.py +++ b/src/haven/instrument/camera.py @@ -1,31 +1,20 @@ import asyncio import logging -import warnings -from typing import Optional, Sequence - -from ophyd import ( - CamBase, - SingleTrigger, - Kind, - ADComponent as ADCpt, - EpicsSignal, - do_not_wait_for_lazy_connection, -) -from ophyd.areadetector.base import EpicsSignalWithRBV as SignalWithRBV +from typing import Sequence + +from ophyd import ADComponent as ADCpt +from ophyd import CamBase, EpicsSignal, Kind, SingleTrigger from ophyd.areadetector.plugins import ( ImagePlugin_V34, - PvaPlugin_V34, OverlayPlugin, + PvaPlugin_V34, ROIPlugin_V34, ) - -from .instrument_registry import registry -from .area_detector import DetectorBase, StatsPlugin_V34, SimDetector, AsyncCamMixin -from .device import await_for_connection, aload_devices, make_device -from .._iconfig import load_config from .. import exceptions - +from .._iconfig import load_config +from .area_detector import AsyncCamMixin, DetectorBase, SimDetector, StatsPlugin_V34 # noqa: F401 +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/delay.py b/src/haven/instrument/delay.py index 01f40823..710751ba 100644 --- a/src/haven/instrument/delay.py +++ b/src/haven/instrument/delay.py @@ -1,6 +1,7 @@ import enum -from ophyd import Device, Component as Cpt, EpicsSignal, EpicsSignalRO, Kind +from ophyd import Component as Cpt +from ophyd import Device, EpicsSignal, EpicsSignalRO, Kind class EpicsSignalWithIO(EpicsSignal): diff --git a/src/haven/instrument/device.py b/src/haven/instrument/device.py index 94a7222b..4b99681b 100644 --- a/src/haven/instrument/device.py +++ b/src/haven/instrument/device.py @@ -1,14 +1,14 @@ +import asyncio import logging import re import time as ttime from typing import Callable, Union -import asyncio -from ophyd import Component, K, Device +from ophyd import Component, Device, K from ophyd.sim import make_fake_device -from .instrument_registry import registry -from .._iconfig import load_config +from .._iconfig import load_config +from .instrument_registry import registry log = logging.getLogger(__name__) @@ -64,7 +64,8 @@ async def make_device(DeviceClass, *args, FakeDeviceClass=None, **kwargs) -> Dev if DeviceClass.__name__ == "VortexEx": raise log.warning( - f"Could not connect to {DeviceClass.__name__} in {round(ttime.monotonic() - t0, 2)} sec: {name}." + f"Could not connect to {DeviceClass.__name__} in" + f" {round(ttime.monotonic() - t0, 2)} sec: {name}." ) log.info(f"Reason for {name} failure: {e}.") return None diff --git a/src/haven/instrument/dxp.py b/src/haven/instrument/dxp.py index a9c89502..599e8e88 100644 --- a/src/haven/instrument/dxp.py +++ b/src/haven/instrument/dxp.py @@ -1,54 +1,27 @@ -from enum import IntEnum -from collections import OrderedDict -from typing import Optional, Sequence -import warnings -import logging import asyncio import time +import warnings +from collections import OrderedDict +from enum import IntEnum +from typing import Optional, Sequence -from ophyd import ( - ADComponent as ADCpt, - OphydObject, - mca, - Device, - EpicsSignal, - EpicsSignalRO, - Component as Cpt, - DynamicDeviceComponent as DDC, - Kind, - Signal, - flyers, -) -from ophyd.areadetector.plugins import NetCDFPlugin_V34 -from ophyd.status import SubscriptionStatus, StatusBase -from ophyd.signal import InternalSignal, DerivedSignal -from apstools.utils import cleanupText -from ophyd.pseudopos import ( - PseudoPositioner, - PseudoSingle, - pseudo_position_argument, - real_position_argument, -) +from ophyd import Component as Cpt +from ophyd import DynamicDeviceComponent as DDC +from ophyd import Kind, Signal, flyers, mca +from ophyd.signal import DerivedSignal, InternalSignal +from ophyd.status import StatusBase, SubscriptionStatus -from .scaler_triggered import ScalerTriggered -from .instrument_registry import registry +from .. import exceptions +from .._iconfig import load_config +from .device import aload_devices, make_device from .fluorescence_detector import ( + MCASumMixin, + ROIMixin, + UseROISignal, XRFMixin, active_kind, - ROIMixin, - MCASumMixin, add_roi_sums, - UseROISignal, -) -from .device import ( - RegexComponent as RECpt, - await_for_connection, - aload_devices, - make_device, ) -from .._iconfig import load_config -from .. import exceptions - __all__ = ["DxpDetector", "load_dxp"] diff --git a/src/haven/instrument/energy_positioner.py b/src/haven/instrument/energy_positioner.py index 53ba9ba2..ae92b1ba 100644 --- a/src/haven/instrument/energy_positioner.py +++ b/src/haven/instrument/energy_positioner.py @@ -1,24 +1,17 @@ import asyncio import logging -from ophyd import ( - PseudoPositioner, - EpicsMotor, - Component as Cpt, - FormattedComponent as FCpt, - PseudoSingle, - PVPositioner, - EpicsSignal, - EpicsSignalRO, -) +from ophyd import Component as Cpt +from ophyd import EpicsMotor, EpicsSignal, EpicsSignalRO +from ophyd import FormattedComponent as FCpt +from ophyd import PseudoPositioner, PseudoSingle, PVPositioner from ophyd.ophydobj import OphydObject from ophyd.pseudopos import pseudo_position_argument, real_position_argument from .._iconfig import load_config +from .device import aload_devices, await_for_connection from .instrument_registry import registry -from .monochromator import Monochromator, IDTracking -from .device import await_for_connection, aload_devices - +from .monochromator import IDTracking, Monochromator log = logging.getLogger(__name__) diff --git a/src/haven/instrument/fluorescence_detector.py b/src/haven/instrument/fluorescence_detector.py index bba157e6..59f1c2ec 100644 --- a/src/haven/instrument/fluorescence_detector.py +++ b/src/haven/instrument/fluorescence_detector.py @@ -6,46 +6,15 @@ """ -from enum import IntEnum +import logging from collections import OrderedDict from typing import Optional, Sequence -from contextlib import contextmanager -import warnings -import logging -import asyncio -import time import numpy as np -from ophyd import ( - mca, - Device, - EpicsSignal, - EpicsSignalRO, - Component as Cpt, - DynamicDeviceComponent as DDC, - Kind, - Signal, - SignalRO, - flyers, -) -from ophyd.signal import InternalSignal, DerivedSignal -from ophyd.areadetector.plugins import NetCDFPlugin_V34 -from ophyd.status import SubscriptionStatus, StatusBase from apstools.utils import cleanupText -from pcdsdevices.signal import MultiDerivedSignal, MultiDerivedSignalRO -from pcdsdevices.type_hints import SignalToValue, OphydDataType - -from .scaler_triggered import ScalerTriggered -from .instrument_registry import registry -from .device import ( - RegexComponent as RECpt, - await_for_connection, - aload_devices, - make_device, -) -from .._iconfig import load_config -from .. import exceptions - +from ophyd import Component as Cpt +from ophyd import Device, Kind +from ophyd.signal import DerivedSignal, InternalSignal __all__ = ["XRFMixin"] diff --git a/src/haven/instrument/heater.py b/src/haven/instrument/heater.py index f4a1180c..5a4586c6 100644 --- a/src/haven/instrument/heater.py +++ b/src/haven/instrument/heater.py @@ -1,17 +1,13 @@ import asyncio import logging -from ophyd import PVPositioner, EpicsSignalRO, EpicsSignalWithRBV, Component as Cpt -from apstools.devices import ( - PTC10PositionerMixin, - PTC10AioChannel as PTC10AioChannelBase, - PTC10TcChannel, -) +from apstools.devices import PTC10AioChannel as PTC10AioChannelBase +from apstools.devices import PTC10PositionerMixin, PTC10TcChannel +from ophyd import Component as Cpt +from ophyd import EpicsSignalRO, EpicsSignalWithRBV, PVPositioner from .._iconfig import load_config -from .instrument_registry import registry -from .device import await_for_connection, aload_devices, make_device - +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/instrument_registry.py b/src/haven/instrument/instrument_registry.py index 7574e511..a4f6f5c2 100644 --- a/src/haven/instrument/instrument_registry.py +++ b/src/haven/instrument/instrument_registry.py @@ -1,16 +1,6 @@ -from typing import Optional, Sequence import logging -import warnings -from itertools import chain -from typing import Sequence -from ophyd import ophydobj from ophydregistry import Registry as InstrumentRegistry -from ophydregistry.exceptions import ( - ComponentNotFound, - MultipleComponentsFound, - InvalidComponentLabel, -) log = logging.getLogger(__name__) diff --git a/src/haven/instrument/ion_chamber.py b/src/haven/instrument/ion_chamber.py index 39dc9745..09c57d95 100644 --- a/src/haven/instrument/ion_chamber.py +++ b/src/haven/instrument/ion_chamber.py @@ -1,49 +1,35 @@ """Holds ion chamber detector descriptions and assignments to EPICS PVs.""" -from typing import Sequence, Generator, Dict -import logging import asyncio -from collections import OrderedDict +import logging +import math import time import warnings -import math +from collections import OrderedDict +from typing import Dict, Generator -import epics -from ophyd import ( - Device, - status, - Signal, - EpicsSignal, - EpicsSignalRO, - PVPositionerPC, - PVPositioner, - PseudoPositioner, - PseudoSingle, - Component as Cpt, - FormattedComponent as FCpt, - Kind, - flyers, -) -from ophyd.signal import InternalSignal, DerivedSignal -from ophyd.ophydobj import OphydObject -from ophyd.pseudopos import pseudo_position_argument, real_position_argument +import numpy as np +import pint +from apstools.devices import SRS570_PreAmplifier +from ophyd import Component as Cpt +from ophyd import Device, EpicsSignal, EpicsSignalRO +from ophyd import FormattedComponent as FCpt +from ophyd import Kind, Signal, flyers, status from ophyd.mca import EpicsMCARecord +from ophyd.ophydobj import OphydObject +from ophyd.signal import DerivedSignal, InternalSignal from ophyd.status import SubscriptionStatus from ophyd.utils.errors import OpException -from apstools.devices import SRS570_PreAmplifier from pcdsdevices.signal import MultiDerivedSignal, MultiDerivedSignalRO -from pcdsdevices.type_hints import SignalToValue, OphydDataType -import numpy as np -import pint +from pcdsdevices.type_hints import OphydDataType, SignalToValue -from .scaler_triggered import ScalerTriggered, ScalerSignal, ScalerSignalRO -from .instrument_registry import registry +from .. import exceptions +from .._iconfig import load_config +from .device import aload_devices, await_for_connection, make_device from .epics import caget -from .device import await_for_connection, aload_devices, make_device +from .instrument_registry import registry from .labjack import AnalogInput -from .._iconfig import load_config -from .. import exceptions - +from .scaler_triggered import ScalerSignalRO, ScalerTriggered log = logging.getLogger(__name__) @@ -166,7 +152,10 @@ def _put_sensitivity_level( new_offset = max(new_level + self.offset_difference, 0) # Check for out of bounds lmin, lmax = (0, 27) - msg = f"Cannot set {self.name} outside range ({lmin}, {lmax}), received {new_level}." + msg = ( + f"Cannot set {self.name} outside range ({lmin}, {lmax}), received" + f" {new_level}." + ) if new_level < lmin: raise exceptions.GainOverflow(msg) elif new_level > lmax: @@ -608,12 +597,16 @@ async def load_ion_chamber( labels={"ion_chambers"}, ) # Ensure the voltmeter is in differential mode to measure pre-amp - try: - ion_chamber.voltmeter.differential.set(1).wait(timeout=1) - except OpException as exc: - msg = f"Could not set voltmeter {ion_chamber.name} channel differential state: {exc}" - log.warning(msg) - warnings.warn(msg) + if hasattr(ion_chamber, 'voltmeter'): + try: + ion_chamber.voltmeter.differential.set(1).wait(timeout=1) + except OpException as exc: + msg = ( + f"Could not set voltmeter {ion_chamber.name} channel differential state:" + f" {exc}" + ) + log.warning(msg) + warnings.warn(msg) return ion_chamber diff --git a/src/haven/instrument/labjack.py b/src/haven/instrument/labjack.py index 1c3d17eb..2b3f8527 100644 --- a/src/haven/instrument/labjack.py +++ b/src/haven/instrument/labjack.py @@ -1,14 +1,8 @@ +from apstools.synApps import EpicsRecordDeviceCommonAll, EpicsRecordInputFields +from ophyd import Device, EpicsSignal +from ophyd import FormattedComponent as FCpt from strenum import StrEnum -from ophyd import ( - Device, - EpicsSignal, - EpicsSignalRO, - Component as Cpt, - FormattedComponent as FCpt, -) -from apstools.synApps import EpicsRecordInputFields, EpicsRecordDeviceCommonAll - class AnalogInput(EpicsRecordInputFields, EpicsRecordDeviceCommonAll): class DiffStates(StrEnum): diff --git a/src/haven/instrument/lerix.py b/src/haven/instrument/lerix.py index f9a8d52c..b6858cd4 100644 --- a/src/haven/instrument/lerix.py +++ b/src/haven/instrument/lerix.py @@ -1,14 +1,15 @@ import asyncio import logging + import numpy as np +from ophyd import Component as Cpt +from ophyd import Device, EpicsMotor +from ophyd import FormattedComponent as FCpt +from ophyd import PseudoPositioner, PseudoSingle from ophyd.pseudopos import pseudo_position_argument, real_position_argument -from ophyd import PseudoPositioner, PseudoSingle, EpicsMotor -from ophyd import Component as Cpt, FormattedComponent as FCpt, Device from .._iconfig import load_config -from .instrument_registry import registry -from .device import await_for_connection, aload_devices, make_device - +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/load_instrument.py b/src/haven/instrument/load_instrument.py index 94454db3..6e8b468a 100644 --- a/src/haven/instrument/load_instrument.py +++ b/src/haven/instrument/load_instrument.py @@ -1,27 +1,27 @@ -from typing import Mapping import asyncio +from typing import Mapping from ophyd import sim -from .instrument_registry import registry as default_registry, InstrumentRegistry +from .._iconfig import load_config +from .aps import load_aps_coros +from .area_detector import load_area_detector_coros +from .camera import load_camera_coros +from .dxp import load_dxp_coros from .energy_positioner import load_energy_positioner_coros -from .motor import load_all_motor_coros, HavenMotor +from .heater import load_heater_coros +from .instrument_registry import InstrumentRegistry +from .instrument_registry import registry as default_registry from .ion_chamber import load_ion_chamber_coros -from .dxp import load_dxp_coros +from .lerix import load_lerix_spectrometer_coros from .monochromator import load_monochromator_coros -from .camera import load_camera_coros +from .motor import HavenMotor, load_all_motor_coros +from .power_supply import load_power_supply_coros from .shutter import load_shutter_coros +from .slits import load_slit_coros from .stage import load_stage_coros -from .aps import load_aps_coros -from .power_supply import load_power_supply_coros from .xray_source import load_xray_source_coros -from .area_detector import load_area_detector_coros -from .slits import load_slit_coros -from .lerix import load_lerix_spectrometer_coros -from .heater import load_heater_coros from .xspress import load_xspress_coros -from .._iconfig import load_config - __all__ = ["load_instrument"] diff --git a/src/haven/instrument/monochromator.py b/src/haven/instrument/monochromator.py index d3e06a7f..d3dc38cf 100644 --- a/src/haven/instrument/monochromator.py +++ b/src/haven/instrument/monochromator.py @@ -1,20 +1,12 @@ import asyncio -from enum import IntEnum import logging +from enum import IntEnum -from ophyd import ( - Device, - Component as Cpt, - FormattedComponent as FCpt, - EpicsMotor, - EpicsSignal, - EpicsSignalRO, -) +from ophyd import Component as Cpt +from ophyd import Device, EpicsMotor, EpicsSignal, EpicsSignalRO -from .instrument_registry import registry from .._iconfig import load_config -from .device import await_for_connection, aload_devices, make_device - +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/motor.py b/src/haven/instrument/motor.py index 5cf40186..3c674864 100644 --- a/src/haven/instrument/motor.py +++ b/src/haven/instrument/motor.py @@ -1,19 +1,13 @@ +import asyncio import logging from typing import Optional -import asyncio -import time -from functools import partial -import io -import contextlib -import epics -from ophyd import EpicsMotor, EpicsSignal, EpicsSignalRO, Component as Cpt, sim +from ophyd import Component as Cpt +from ophyd import EpicsMotor, EpicsSignal, EpicsSignalRO -from .epics import caget from .._iconfig import load_config -from .device import await_for_connection, aload_devices, make_device -from .instrument_registry import registry - +from .device import aload_devices, make_device +from .epics import caget log = logging.getLogger(__name__) @@ -94,7 +88,6 @@ async def load_motor(prefix: str, motor_num: int, ioc_name: str = None): # Get the motor name from the description PV try: name = await caget(f"{pv}.DESC") - print(name) except asyncio.exceptions.TimeoutError: if not config["beamline"]["is_connected"]: # Beamline is not connected, so just use a generic name @@ -105,7 +98,7 @@ async def load_motor(prefix: str, motor_num: int, ioc_name: str = None): return else: log.debug(f"Resolved motor {pv} to '{name}'") - + # Create the motor device if name == f"motor {motor_num+1}": # It's an unnamed motor, so skip it diff --git a/src/haven/instrument/power_supply.py b/src/haven/instrument/power_supply.py index e341e050..78bb4621 100644 --- a/src/haven/instrument/power_supply.py +++ b/src/haven/instrument/power_supply.py @@ -1,19 +1,12 @@ -import logging import asyncio +import logging -from ophyd import ( - Device, - Component as Cpt, - FormattedComponent as FCpt, - EpicsSignal, - EpicsSignalRO, - EpicsMotor, -) +from ophyd import Device, EpicsSignal, EpicsSignalRO +from ophyd import FormattedComponent as FCpt from .._iconfig import load_config +from .device import aload_devices, await_for_connection from .instrument_registry import registry -from .device import await_for_connection, aload_devices - log = logging.getLogger(__name__) diff --git a/src/haven/instrument/scaler_triggered.py b/src/haven/instrument/scaler_triggered.py index f96baf2f..a0988203 100644 --- a/src/haven/instrument/scaler_triggered.py +++ b/src/haven/instrument/scaler_triggered.py @@ -1,11 +1,4 @@ -from ophyd import ( - Device, - Component, - FormattedComponent, - EpicsSignal, - EpicsSignalRO, -) - +from ophyd import EpicsSignal, EpicsSignalRO __all__ = ["ScalerTriggered"] diff --git a/src/haven/instrument/shutter.py b/src/haven/instrument/shutter.py index 82d991bb..de258e61 100644 --- a/src/haven/instrument/shutter.py +++ b/src/haven/instrument/shutter.py @@ -1,13 +1,10 @@ -import logging import asyncio -from bluesky import suspenders -from ophyd import FormattedComponent as FCpt, EpicsSignal +import logging + from apstools.devices.shutters import ApsPssShutterWithStatus as Shutter from .._iconfig import load_config -from .instrument_registry import registry -from .device import await_for_connection, aload_devices, make_device - +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/slits.py b/src/haven/instrument/slits.py index 2e32ec9f..a6770395 100644 --- a/src/haven/instrument/slits.py +++ b/src/haven/instrument/slits.py @@ -1,12 +1,11 @@ -import logging import asyncio +import logging from apstools.synApps.db_2slit import Optics2Slit2D_HV from .._iconfig import load_config +from .device import aload_devices, await_for_connection from .instrument_registry import registry -from .device import await_for_connection, aload_devices - log = logging.getLogger(__name__) diff --git a/src/haven/instrument/stage.py b/src/haven/instrument/stage.py index 8e882fb6..aa63857c 100644 --- a/src/haven/instrument/stage.py +++ b/src/haven/instrument/stage.py @@ -1,34 +1,12 @@ -import threading -import time -import logging import asyncio -import math -from typing import Generator, Dict -from datetime import datetime, timedelta -from collections import OrderedDict - -from ophyd import ( - Device, - FormattedComponent as FCpt, - EpicsMotor, - Component as Cpt, - Signal, - SignalRO, - Kind, - EpicsSignal, - flyers, -) -from ophyd.status import SubscriptionStatus, AndStatus, StatusBase -from apstools.synApps.asyn import AsynRecord -import pint -import numpy as np - -from .delay import DG645Delay -from .instrument_registry import registry -from .._iconfig import load_config -from ..exceptions import InvalidScanParameters -from .device import await_for_connection, aload_devices, make_device +import logging +from ophyd import Device, EpicsMotor +from ophyd import FormattedComponent as FCpt + +from .._iconfig import load_config +from .device import aload_devices, make_device +from .instrument_registry import registry __all__ = ["XYStage", "load_stages"] @@ -36,7 +14,6 @@ log = logging.getLogger(__name__) - @registry.register class XYStage(Device): """An XY stage with two motors operating in orthogonal directions. diff --git a/src/haven/instrument/xray_source.py b/src/haven/instrument/xray_source.py index a14729b3..9fa4847d 100644 --- a/src/haven/instrument/xray_source.py +++ b/src/haven/instrument/xray_source.py @@ -1,12 +1,10 @@ -import logging import asyncio +import logging + from apstools.devices.aps_undulator import ApsUndulator -import epics -from .instrument_registry import registry from .._iconfig import load_config -from .device import await_for_connection, aload_devices, make_device - +from .device import aload_devices, make_device log = logging.getLogger(__name__) diff --git a/src/haven/instrument/xspress.py b/src/haven/instrument/xspress.py index 3dea0ca2..ef155fa4 100644 --- a/src/haven/instrument/xspress.py +++ b/src/haven/instrument/xspress.py @@ -1,70 +1,35 @@ -from enum import IntEnum -from functools import partial -import logging import asyncio -from typing import Optional, Sequence, Dict -from collections import OrderedDict +import logging import time +from collections import OrderedDict +from enum import IntEnum +from functools import partial +from typing import Dict, Optional, Sequence import numpy as np import pandas as pd from apstools.devices import CamMixin_V34, SingleTrigger_V34 -from ophyd import ( - ADComponent as ADCpt, - DetectorBase, - CamBase, - SimDetectorCam, - Lambda750kCam, - EigerDetectorCam, - Component as Cpt, - EpicsSignal, - EpicsSignalRO, - EpicsSignalWithRBV, - DynamicDeviceComponent as DDC, - SingleTrigger, - Kind, - OphydObject, - Device, - Signal, -) -from ophyd.status import SubscriptionStatus, StatusBase, AndStatus -from ophyd.signal import InternalSignal, DerivedSignal +from ophyd import ADComponent as ADCpt +from ophyd import Component as Cpt +from ophyd import DetectorBase, Device +from ophyd import DynamicDeviceComponent as DDC +from ophyd import EpicsSignal, EpicsSignalRO, Kind from ophyd.areadetector.base import EpicsSignalWithRBV as SignalWithRBV -from ophyd.areadetector.filestore_mixins import FileStoreHDF5IterativeWrite -from ophyd.areadetector.plugins import ( - HDF5Plugin_V34, - HDF5Plugin_V31, - ImagePlugin_V34, - ImagePlugin_V31, - PvaPlugin_V34, - PvaPlugin_V31, - TIFFPlugin_V34, - TIFFPlugin_V31, - ROIPlugin_V34, - ROIPlugin_V31, - StatsPlugin_V31 as OphydStatsPlugin_V31, - StatsPlugin_V34 as OphydStatsPlugin_V34, - OverlayPlugin, -) -from pcdsdevices.signal import MultiDerivedSignal, MultiDerivedSignalRO -from pcdsdevices.type_hints import SignalToValue, OphydDataType +from ophyd.signal import InternalSignal +from ophyd.status import StatusBase, SubscriptionStatus +from pcdsdevices.signal import MultiDerivedSignal +from pcdsdevices.type_hints import OphydDataType, SignalToValue from .._iconfig import load_config -from .instrument_registry import registry +from .device import RegexComponent as RECpt +from .device import aload_devices, make_device from .fluorescence_detector import ( - XRFMixin, - ROIMixin, MCASumMixin, - add_roi_sums, + ROIMixin, UseROISignal, + XRFMixin, + add_roi_sums, ) -from .device import ( - await_for_connection, - aload_devices, - make_device, - RegexComponent as RECpt, -) - __all__ = ["load_xspress", "Xspress3Detector", "ROI"] diff --git a/src/haven/motor_position.py b/src/haven/motor_position.py index 84ce5550..e10cc905 100644 --- a/src/haven/motor_position.py +++ b/src/haven/motor_position.py @@ -1,17 +1,16 @@ -from typing import Optional, Sequence import logging +import time +from datetime import datetime +from typing import Optional, Sequence -import pymongo -from pydantic import BaseModel import intake -from bson.objectid import ObjectId +import pymongo from bluesky import plan_stubs as bps +from bson.objectid import ObjectId +from pydantic import BaseModel -from .instrument.instrument_registry import registry from . import exceptions - -import time -from datetime import datetime +from .instrument.instrument_registry import registry log = logging.getLogger(__name__) diff --git a/src/haven/plans/align_motor.py b/src/haven/plans/align_motor.py index e7c44708..3f3f51f0 100644 --- a/src/haven/plans/align_motor.py +++ b/src/haven/plans/align_motor.py @@ -1,11 +1,11 @@ +import logging import time import warnings -import logging -from bluesky.preprocessors import subs_decorator, subs_wrapper -from bluesky.callbacks import best_effort -from bluesky import plan_stubs as bps from apstools.plans.alignment import lineup +from bluesky import plan_stubs as bps +from bluesky.callbacks import best_effort +from bluesky.preprocessors import subs_wrapper from ..instrument.instrument_registry import registry from ..preprocessors import shutter_suspend_decorator diff --git a/src/haven/plans/align_slits.py b/src/haven/plans/align_slits.py index e7fd9a45..6f8bbdcb 100644 --- a/src/haven/plans/align_slits.py +++ b/src/haven/plans/align_slits.py @@ -6,12 +6,12 @@ import logging import warnings -import numpy as np import lmfit -from bluesky import plans as bp, plan_stubs as bps -from bluesky.preprocessors import subs_decorator +import numpy as np +from bluesky import plan_stubs as bps +from bluesky import plans as bp from bluesky.callbacks import LiveFit - +from bluesky.preprocessors import subs_decorator __all__ = ["align_slits"] diff --git a/src/haven/plans/auto_gain.py b/src/haven/plans/auto_gain.py index 8c15ce67..85117be1 100644 --- a/src/haven/plans/auto_gain.py +++ b/src/haven/plans/auto_gain.py @@ -1,6 +1,7 @@ import numpy as np import pandas as pd -from bluesky import plans as bp, plan_stubs as bps +from bluesky import plan_stubs as bps +from bluesky import plans as bp from bluesky.callbacks.core import CollectThenCompute from bluesky.preprocessors import subs_decorator diff --git a/src/haven/plans/beam_properties.py b/src/haven/plans/beam_properties.py index de27fc00..7a126e18 100644 --- a/src/haven/plans/beam_properties.py +++ b/src/haven/plans/beam_properties.py @@ -3,8 +3,8 @@ import matplotlib.pyplot as plt import numpy as np -from lmfit.models import StepModel, GaussianModel from bluesky import plans as bp +from lmfit.models import GaussianModel, StepModel from ..instrument.instrument_registry import registry diff --git a/src/haven/plans/energy_scan.py b/src/haven/plans/energy_scan.py index 4abda2b1..5db8e939 100644 --- a/src/haven/plans/energy_scan.py +++ b/src/haven/plans/energy_scan.py @@ -3,20 +3,17 @@ """ import logging -import warnings -from typing import Sequence, Union, Mapping from collections import ChainMap +from typing import Mapping, Sequence, Union -from bluesky import plans as bp import numpy as np +from bluesky import plans as bp -from .. import merge_ranges from .._iconfig import load_config -from ..instrument import registry from ..constants import edge_energy +from ..instrument import registry +from ..preprocessors import baseline_decorator from ..typing import DetectorList -from ..preprocessors import baseline_decorator, shutter_suspend_decorator - __all__ = ["energy_scan"] diff --git a/src/haven/plans/fly.py b/src/haven/plans/fly.py index 1971d12a..e2dc4cad 100644 --- a/src/haven/plans/fly.py +++ b/src/haven/plans/fly.py @@ -1,16 +1,15 @@ from collections import OrderedDict, abc -from functools import partial -from typing import Sequence, Mapping, Union, Optional +from typing import Mapping, Sequence, Union import numpy as np -from bluesky import plans as bp, plan_stubs as bps, plan_patterns, preprocessors as bpp +from bluesky import plan_patterns +from bluesky import plan_stubs as bps +from bluesky import plans as bp +from bluesky import preprocessors as bpp from ophyd import Device from ophyd.flyers import FlyerInterface from ophyd.status import StatusBase -from ..preprocessors import baseline_decorator, shutter_suspend_decorator - - __all__ = ["fly_scan", "grid_fly_scan"] diff --git a/src/haven/plans/mono_ID_calibration.py b/src/haven/plans/mono_ID_calibration.py index 242c3d4a..54c7fa39 100644 --- a/src/haven/plans/mono_ID_calibration.py +++ b/src/haven/plans/mono_ID_calibration.py @@ -1,18 +1,17 @@ -from typing import Sequence, Optional -import warnings import logging +import warnings +from typing import Optional, Sequence -from bluesky.callbacks.best_effort import BestEffortCallback -from bluesky import plan_stubs as bps import pandas as pd +from bluesky.callbacks.best_effort import BestEffortCallback from lmfit.model import Model from lmfit.models import QuadraticModel from haven.typing import Motor + from ..instrument.instrument_registry import registry +from .align_motor import align_motor, align_pitch2 from .set_energy import set_energy -from .align_motor import align_pitch2, align_motor - __all__ = ["mono_ID_calibration"] diff --git a/src/haven/plans/mono_gap_calibration.py b/src/haven/plans/mono_gap_calibration.py index a29572e8..149293aa 100644 --- a/src/haven/plans/mono_gap_calibration.py +++ b/src/haven/plans/mono_gap_calibration.py @@ -1,21 +1,18 @@ import datetime as dt -from pathlib import Path import logging +from pathlib import Path from bluesky.callbacks import LiveFit, best_effort, fitting, mpl_plotting from bluesky.preprocessors import subs_decorator -from bluesky import plan_stubs as bps -from apstools.plans.alignment import lineup -from matplotlib import pyplot as plt from lmfit.models import StepModel +from matplotlib import pyplot as plt +from .._iconfig import load_config from ..instrument.instrument_registry import registry -from .set_energy import set_energy +from .align_motor import align_pitch2 from .auto_gain import auto_gain from .beam_properties import knife_scan -from .._iconfig import load_config -from .align_motor import align_pitch2 - +from .set_energy import set_energy log = logging.getLogger(__name__) diff --git a/src/haven/plans/record_dark_current.py b/src/haven/plans/record_dark_current.py index b34b9c6a..82c413b8 100644 --- a/src/haven/plans/record_dark_current.py +++ b/src/haven/plans/record_dark_current.py @@ -1,7 +1,7 @@ -from bluesky import plans as bp, plan_stubs as bps +from bluesky import plan_stubs as bps -from .shutters import open_shutters, close_shutters from ..instrument.instrument_registry import registry +from .shutters import close_shutters, open_shutters def record_dark_current(ion_chambers, shutters, time): diff --git a/src/haven/plans/set_energy.py b/src/haven/plans/set_energy.py index fa4ff661..a40aff4a 100644 --- a/src/haven/plans/set_energy.py +++ b/src/haven/plans/set_energy.py @@ -1,12 +1,10 @@ -from typing import Union, Sequence +from typing import Union from bluesky import plan_stubs as bps -from ophyd import Device +from .. import exceptions from ..instrument.instrument_registry import registry from ..typing import DetectorList -from .. import exceptions - __all__ = ["set_energy"] diff --git a/src/haven/plans/shutters.py b/src/haven/plans/shutters.py index ed437b33..b71a8984 100644 --- a/src/haven/plans/shutters.py +++ b/src/haven/plans/shutters.py @@ -1,5 +1,6 @@ +from typing import Literal, Sequence, Union + from bluesky import plan_stubs as bps -from typing import Literal, Union, Sequence from ..instrument.instrument_registry import registry from ..typing import Motor diff --git a/src/haven/plans/xafs_scan.py b/src/haven/plans/xafs_scan.py index cf05f36b..094b12e2 100644 --- a/src/haven/plans/xafs_scan.py +++ b/src/haven/plans/xafs_scan.py @@ -3,18 +3,16 @@ """ -from typing import Union, Sequence, Optional, Mapping -from collections import ChainMap -import warnings import logging +import warnings +from collections import ChainMap +from typing import Mapping, Optional, Sequence, Union -import numpy as np - -from ..energy_ranges import ERange, KRange, merge_ranges from .. import exceptions -from .energy_scan import energy_scan +from ..energy_ranges import ERange, KRange, merge_ranges +from ..preprocessors import baseline_decorator from ..typing import DetectorList -from ..preprocessors import baseline_decorator, shutter_suspend_decorator +from .energy_scan import energy_scan log = logging.getLogger(__name__) diff --git a/src/haven/preprocessors.py b/src/haven/preprocessors.py index ff278bdc..d9b79f05 100644 --- a/src/haven/preprocessors.py +++ b/src/haven/preprocessors.py @@ -1,30 +1,24 @@ """Tools for modifying plans and data streams as they are generated.""" -from typing import Union, Sequence, Iterable -from collections import ChainMap -import pkg_resources +import getpass +import logging import os import socket -import getpass import warnings -import logging +from collections import ChainMap +from typing import Iterable, Sequence, Union -from bluesky.preprocessors import ( - baseline_wrapper as bluesky_baseline_wrapper, - finalize_wrapper, - suspend_wrapper, -) -from bluesky.suspenders import SuspendBoolLow -from bluesky.utils import make_decorator, Msg -from bluesky.preprocessors import msg_mutator import epics +import pkg_resources +from bluesky.preprocessors import baseline_wrapper as bluesky_baseline_wrapper +from bluesky.preprocessors import finalize_wrapper, msg_mutator +from bluesky.suspenders import SuspendBoolLow +from bluesky.utils import Msg, make_decorator - -from .instrument.instrument_registry import registry -from .exceptions import ComponentNotFound from ._iconfig import load_config - +from .exceptions import ComponentNotFound +from .instrument.instrument_registry import registry log = logging.getLogger() diff --git a/src/haven/run_engine.py b/src/haven/run_engine.py index 84bfb5af..3de001bb 100644 --- a/src/haven/run_engine.py +++ b/src/haven/run_engine.py @@ -1,39 +1,17 @@ import logging -import warnings -from bluesky import RunEngine as BlueskyRunEngine, suspenders -from bluesky.callbacks.best_effort import BestEffortCallback import databroker +from bluesky import RunEngine as BlueskyRunEngine +from bluesky import suspenders +from bluesky.callbacks.best_effort import BestEffortCallback -from ._iconfig import load_config -from .preprocessors import inject_haven_md_wrapper from .exceptions import ComponentNotFound from .instrument.instrument_registry import registry -from .exceptions import ComponentNotFound +from .preprocessors import inject_haven_md_wrapper log = logging.getLogger(__name__) -# class RunEngine(BlueskyRunEngine): -# def __init__(self, *args, connect_databroker=True, **kwargs): -# super().__init__(*args, **kwargs) -# if connect_databroker: -# # Load the databroker catalog and set up data saving -# catalog_name = load_config()["database"]["databroker"]["catalog"] -# try: -# catalog = databroker.catalog[catalog_name] -# self.subscribe(catalog.v1.insert) -# except Exception as e: -# msg = ( -# f"Data are not being saved! Could not load databroker catalog: {e}" -# ) -# log.error(msg) -# warnings.warn(msg) -# raise RuntimeError(msg) -# # Add metadata pre-processor -# self.preprocessors.append(inject_haven_md_wrapper) - - catalog = None diff --git a/src/haven/simulated_ioc.py b/src/haven/simulated_ioc.py index 414b9c28..78c8b9ec 100644 --- a/src/haven/simulated_ioc.py +++ b/src/haven/simulated_ioc.py @@ -1,30 +1,22 @@ #!/usr/bin/env python3 +import contextlib +import importlib +import logging import os import signal -import logging -from textwrap import dedent - import time -from subprocess import Popen, PIPE -from typing import Optional, List, Dict, Tuple, Any -import contextlib -import importlib from pathlib import Path +from subprocess import PIPE, Popen +from textwrap import dedent +from typing import Any, Dict, List, Optional, Tuple -from tqdm import tqdm from caproto import ChannelType -from caproto.server import ( - PVGroup, - template_arg_parser, - pvproperty, - run, - records, -) +from caproto.server import PVGroup, pvproperty, records, run, template_arg_parser from epics import caget +from tqdm import tqdm from . import exceptions - log = logging.getLogger(__name__) diff --git a/src/haven/tests/ioc_apsbss.py b/src/haven/tests/ioc_apsbss.py index a682cc50..5c581f00 100644 --- a/src/haven/tests/ioc_apsbss.py +++ b/src/haven/tests/ioc_apsbss.py @@ -1,17 +1,12 @@ #!/usr/bin/env python3 -from caproto import ChannelType from caproto.server import ( PVGroup, - SubGroup, + PvpropertyInteger, + PvpropertyString, ioc_arg_parser, pvproperty, run, - PvpropertyString, - PvpropertyInteger, ) -from ophyd.tests.fake_motor_ioc import FakeMotorIOC - -from haven.simulated_ioc import ResponsiveMotorFields # , IOC as IOC_ class SimpleGroup(PVGroup): diff --git a/src/haven/tests/ioc_area_detector.py b/src/haven/tests/ioc_area_detector.py index 1f221808..4f15f933 100644 --- a/src/haven/tests/ioc_area_detector.py +++ b/src/haven/tests/ioc_area_detector.py @@ -1,15 +1,13 @@ #!/usr/bin/env python3 from caproto.server import ( PVGroup, + PvpropertyInteger, SubGroup, ioc_arg_parser, pvproperty, run, - PvpropertyInteger, ) -from ophyd.tests.scaler_ioc import EpicsScalerGroup - class AreaDetectorGroup(PVGroup): """An IOC matching an EPICS area detector. diff --git a/src/haven/tests/ioc_dxp.py b/src/haven/tests/ioc_dxp.py index 2d30c2e4..69aa0d5c 100755 --- a/src/haven/tests/ioc_dxp.py +++ b/src/haven/tests/ioc_dxp.py @@ -1,20 +1,19 @@ #!/usr/bin/env python3 -from functools import partial import logging +from functools import partial import numpy as np +from caproto import ChannelType from caproto.server import ( PVGroup, SubGroup, get_pv_pair_wrapper, ioc_arg_parser, pvproperty, - PvpropertyDouble, run, ) -from caproto import ChannelType -from ophyd.tests.mca_ioc import EpicsMCAGroup, EpicsDXPGroup, MCAROIGroup +from ophyd.tests.mca_ioc import EpicsDXPGroup, EpicsMCAGroup, MCAROIGroup from peakutils.peak import gaussian pvproperty_with_rbv = get_pv_pair_wrapper(setpoint_suffix="", readback_suffix="_RBV") diff --git a/src/haven/tests/ioc_mono.py b/src/haven/tests/ioc_mono.py index 16fec2d1..55d72c35 100644 --- a/src/haven/tests/ioc_mono.py +++ b/src/haven/tests/ioc_mono.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -from caproto import ChannelType -from caproto.server import PVGroup, SubGroup, ioc_arg_parser, pvproperty, run -from ophyd.tests.fake_motor_ioc import FakeMotorIOC +from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run from haven.simulated_ioc import ResponsiveMotorFields # , IOC as IOC_ diff --git a/src/haven/tests/ioc_motor.py b/src/haven/tests/ioc_motor.py index 53b791a5..9dce4692 100644 --- a/src/haven/tests/ioc_motor.py +++ b/src/haven/tests/ioc_motor.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 -from caproto import ChannelType -from caproto.server import PVGroup, SubGroup, ioc_arg_parser, pvproperty, run +from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run from haven.simulated_ioc import ResponsiveMotorFields diff --git a/src/haven/tests/ioc_preamp.py b/src/haven/tests/ioc_preamp.py index 38662c96..02d5b83c 100644 --- a/src/haven/tests/ioc_preamp.py +++ b/src/haven/tests/ioc_preamp.py @@ -1,17 +1,6 @@ #!/usr/bin/env python3 from caproto import ChannelType -from caproto.server import ( - PVGroup, - SubGroup, - ioc_arg_parser, - pvproperty, - run, - PvpropertyString, - PvpropertyInteger, -) -from ophyd.tests.fake_motor_ioc import FakeMotorIOC - -from haven.simulated_ioc import ResponsiveMotorFields # , IOC as IOC_ +from caproto.server import PVGroup, SubGroup, ioc_arg_parser, pvproperty, run class PreampsGroup(PVGroup): diff --git a/src/haven/tests/ioc_ptc10.py b/src/haven/tests/ioc_ptc10.py index 415d1d86..1f06ea64 100644 --- a/src/haven/tests/ioc_ptc10.py +++ b/src/haven/tests/ioc_ptc10.py @@ -1,9 +1,6 @@ #!/usr/bin/env python3 -from caproto import ChannelType from caproto.server import PVGroup, SubGroup, ioc_arg_parser, pvproperty, run -from ophyd.tests.scaler_ioc import EpicsScalerGroup - class PTC10Group(PVGroup): """ diff --git a/src/haven/tests/ioc_scaler.py b/src/haven/tests/ioc_scaler.py index 12681b4e..2fca9c03 100644 --- a/src/haven/tests/ioc_scaler.py +++ b/src/haven/tests/ioc_scaler.py @@ -1,7 +1,5 @@ #!/usr/bin/env python3 -from caproto import ChannelType from caproto.server import PVGroup, SubGroup, ioc_arg_parser, pvproperty, run - from ophyd.tests.scaler_ioc import EpicsScalerGroup diff --git a/src/haven/tests/ioc_simple.py b/src/haven/tests/ioc_simple.py index e1a1e667..c60d3029 100644 --- a/src/haven/tests/ioc_simple.py +++ b/src/haven/tests/ioc_simple.py @@ -1,16 +1,5 @@ #!/usr/bin/env python3 -from caproto import ChannelType -from caproto.server import ( - PVGroup, - SubGroup, - ioc_arg_parser, - pvproperty, - run, - PvpropertyDouble, -) -from ophyd.tests.fake_motor_ioc import FakeMotorIOC - -from haven.simulated_ioc import ResponsiveMotorFields # , IOC as IOC_ +from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run class SimpleGroup(PVGroup): diff --git a/src/haven/tests/ioc_undulator.py b/src/haven/tests/ioc_undulator.py index 40a012c2..6b805aa4 100644 --- a/src/haven/tests/ioc_undulator.py +++ b/src/haven/tests/ioc_undulator.py @@ -1,14 +1,5 @@ #!/usr/bin/env python3 -from caproto import ChannelType -from caproto.server import ( - PVGroup, - SubGroup, - ioc_arg_parser, - pvproperty, - run, - PvpropertyDouble, -) -from ophyd.tests.fake_motor_ioc import FakeMotorIOC +from caproto.server import PVGroup, PvpropertyDouble, ioc_arg_parser, pvproperty, run from haven.simulated_ioc import ResponsiveMotorFields # , IOC as IOC_ diff --git a/src/haven/tests/test_aerotech.py b/src/haven/tests/test_aerotech.py index 081bb599..2959b2ce 100644 --- a/src/haven/tests/test_aerotech.py +++ b/src/haven/tests/test_aerotech.py @@ -1,12 +1,17 @@ -from unittest import mock from collections import OrderedDict +from unittest import mock import numpy as np import pytest from ophyd import StatusBase -from haven.instrument.aerotech import AerotechFlyer, AerotechStage, load_aerotech_stages, ureg from haven import exceptions +from haven.instrument.aerotech import ( + AerotechFlyer, + AerotechStage, + load_aerotech_stages, + ureg, +) def test_load_aerotech_stage(sim_registry): diff --git a/src/haven/tests/test_align_motor.py b/src/haven/tests/test_align_motor.py index d76cb750..2719fbc5 100644 --- a/src/haven/tests/test_align_motor.py +++ b/src/haven/tests/test_align_motor.py @@ -1,13 +1,9 @@ -import time import pytest - -import matplotlib.pyplot as plt -from bluesky.callbacks.best_effort import BestEffortCallback -from bluesky.callbacks.fitting import PeakStats from bluesky import RunEngine +from bluesky.callbacks.best_effort import BestEffortCallback from ophyd import sim -from haven import align_motor, align_pitch2, registry +from haven import align_motor # from run_engine import RunEngineStub diff --git a/src/haven/tests/test_aps.py b/src/haven/tests/test_aps.py index 8d7bd5eb..0a012a78 100644 --- a/src/haven/tests/test_aps.py +++ b/src/haven/tests/test_aps.py @@ -1,8 +1,4 @@ -from unittest import mock - -import pytest - -from haven.instrument import aps, device +from haven.instrument import aps def test_load_aps(sim_registry): diff --git a/src/haven/tests/test_area_detector.py b/src/haven/tests/test_area_detector.py index 6a4488a4..13c84540 100644 --- a/src/haven/tests/test_area_detector.py +++ b/src/haven/tests/test_area_detector.py @@ -1,5 +1,3 @@ -from ophyd.device import do_not_wait_for_lazy_connection - from haven.instrument.area_detector import load_area_detectors diff --git a/src/haven/tests/test_beam_properties.py b/src/haven/tests/test_beam_properties.py index 5bda7909..8d05ec51 100644 --- a/src/haven/tests/test_beam_properties.py +++ b/src/haven/tests/test_beam_properties.py @@ -1,7 +1,6 @@ -import pytest import numpy as np -import matplotlib.pyplot as plt -from ophyd.sim import motor1, det1, det2 +import pytest +from ophyd.sim import det1, det2, motor1 from haven.plans.beam_properties import fit_step, knife_scan diff --git a/src/haven/tests/test_camera.py b/src/haven/tests/test_camera.py index bd9821b5..0199e61b 100644 --- a/src/haven/tests/test_camera.py +++ b/src/haven/tests/test_camera.py @@ -1,9 +1,8 @@ from ophyd import DetectorBase -from haven import registry, load_config +from haven import load_config, registry from haven.instrument.camera import AravisDetector, load_cameras - PREFIX = "255idgigeA:" diff --git a/src/haven/tests/test_device.py b/src/haven/tests/test_device.py index 25352ecd..8dcb6cae 100644 --- a/src/haven/tests/test_device.py +++ b/src/haven/tests/test_device.py @@ -1,8 +1,8 @@ import pytest -from ophyd import sim, EpicsMotor +from ophyd import EpicsMotor, sim -from haven.instrument.load_instrument import load_simulated_devices from haven.instrument.device import make_device +from haven.instrument.load_instrument import load_simulated_devices from haven.instrument.motor import HavenMotor diff --git a/src/haven/tests/test_energy_positioner.py b/src/haven/tests/test_energy_positioner.py index 46b2f540..c33a7165 100644 --- a/src/haven/tests/test_energy_positioner.py +++ b/src/haven/tests/test_energy_positioner.py @@ -1,7 +1,6 @@ import time import pytest -import epics from ophyd.sim import instantiate_fake_device from haven.instrument.energy_positioner import EnergyPositioner diff --git a/src/haven/tests/test_energy_ranges.py b/src/haven/tests/test_energy_ranges.py index c42e94a7..32820934 100644 --- a/src/haven/tests/test_energy_ranges.py +++ b/src/haven/tests/test_energy_ranges.py @@ -1,11 +1,10 @@ -import unittest import logging +import unittest import numpy as np from haven import ERange, KRange, merge_ranges - logging.basicConfig(level=logging.INFO) diff --git a/src/haven/tests/test_energy_xafs_scan.py b/src/haven/tests/test_energy_xafs_scan.py index b9a73c30..c6eac4b8 100644 --- a/src/haven/tests/test_energy_xafs_scan.py +++ b/src/haven/tests/test_energy_xafs_scan.py @@ -1,10 +1,8 @@ +import numpy as np import pytest -import time - from ophyd import sim -import numpy as np -from haven import align_slits, energy_scan, xafs_scan, registry, KRange +from haven import KRange, energy_scan, xafs_scan @pytest.fixture() @@ -83,7 +81,7 @@ def test_energy_scan_basics(mono_motor, id_gap_motor, energies, RE): result = RE(scan) # Check that the mono and ID gap ended up in the right position # time.sleep(1.0) - assert mono_motor.readback.get() == np.max(energies) + assert mono_motor.readback.get() == np.max(energies) # assert mono_motor.get().readback == np.max(energies) assert id_gap_motor.get().readback == np.max(energies) assert I0_exposure.get().readback == exposure_time diff --git a/src/haven/tests/test_fluorescence_detectors.py b/src/haven/tests/test_fluorescence_detectors.py index c7d32938..5d6f8ee9 100644 --- a/src/haven/tests/test_fluorescence_detectors.py +++ b/src/haven/tests/test_fluorescence_detectors.py @@ -7,21 +7,16 @@ """ import logging -from pathlib import Path -import asyncio -from unittest.mock import MagicMock import time +from pathlib import Path import numpy as np import pytest -from epics import caget -from ophyd import Kind, DynamicDeviceComponent as DDC, OphydObject, Signal -from bluesky import plans as bp +from ophyd import OphydObject, Signal -from haven.instrument.dxp import parse_xmap_buffer, load_dxp +from haven.instrument.dxp import load_dxp, parse_xmap_buffer from haven.instrument.xspress import load_xspress - DETECTORS = ["dxp", "xspress"] # DETECTORS = ['dxp'] diff --git a/src/haven/tests/test_fly_plans.py b/src/haven/tests/test_fly_plans.py index 5a285a4e..50848701 100644 --- a/src/haven/tests/test_fly_plans.py +++ b/src/haven/tests/test_fly_plans.py @@ -1,11 +1,10 @@ -from unittest.mock import MagicMock from collections import OrderedDict +from unittest.mock import MagicMock -from ophyd import sim -from bluesky import plan_patterns import numpy as np +from ophyd import sim -from haven.plans.fly import fly_scan, grid_fly_scan, FlyerCollector +from haven.plans.fly import FlyerCollector, fly_scan, grid_fly_scan def test_set_fly_params(aerotech_flyer): diff --git a/src/haven/tests/test_heater.py b/src/haven/tests/test_heater.py index 9edb2543..0eeed293 100644 --- a/src/haven/tests/test_heater.py +++ b/src/haven/tests/test_heater.py @@ -1,8 +1,4 @@ -import time - -from epics import caget, caput -from haven.instrument.heater import CapillaryHeater, load_heaters - +from haven.instrument.heater import load_heaters PREFIX = "255idptc10:" diff --git a/src/haven/tests/test_iconfig.py b/src/haven/tests/test_iconfig.py index 1225acfd..840c4a82 100644 --- a/src/haven/tests/test_iconfig.py +++ b/src/haven/tests/test_iconfig.py @@ -1,9 +1,9 @@ +import importlib import os from pathlib import Path -import importlib from haven import _iconfig -from haven._iconfig import load_config, print_config_value, beamline_connected +from haven._iconfig import beamline_connected, load_config, print_config_value def test_default_values(): diff --git a/src/haven/tests/test_instrument_registry.py b/src/haven/tests/test_instrument_registry.py index 9f3f96d4..0f85176c 100644 --- a/src/haven/tests/test_instrument_registry.py +++ b/src/haven/tests/test_instrument_registry.py @@ -1,9 +1,8 @@ import pytest - -from ophyd import sim, Device, EpicsMotor +from ophyd import Device, EpicsMotor, sim from haven.instrument import InstrumentRegistry -from haven.instrument.instrument_registry import ( +from haven.exceptions import ( ComponentNotFound, MultipleComponentsFound, ) diff --git a/src/haven/tests/test_ion_chamber.py b/src/haven/tests/test_ion_chamber.py index 5871163e..d0501139 100644 --- a/src/haven/tests/test_ion_chamber.py +++ b/src/haven/tests/test_ion_chamber.py @@ -1,12 +1,9 @@ -import pytest import time -import warnings import numpy as np +import pytest from haven.instrument import ion_chamber -from haven import exceptions -import epics def test_gain_level(sim_ion_chamber): diff --git a/src/haven/tests/test_lerix.py b/src/haven/tests/test_lerix.py index 2b3e0b66..74224086 100644 --- a/src/haven/tests/test_lerix.py +++ b/src/haven/tests/test_lerix.py @@ -1,13 +1,9 @@ -from unittest import mock import time -from epics import caget import pytest from ophyd.sim import instantiate_fake_device from haven.instrument import lerix -import haven - um_per_mm = 1000 diff --git a/src/haven/tests/test_mono_ID_calibration_plan.py b/src/haven/tests/test_mono_ID_calibration_plan.py index 5840d4b2..9558ede4 100644 --- a/src/haven/tests/test_mono_ID_calibration_plan.py +++ b/src/haven/tests/test_mono_ID_calibration_plan.py @@ -1,8 +1,7 @@ from unittest.mock import MagicMock + import pytest from ophyd import sim -from bluesky.callbacks.best_effort import BestEffortCallback -from lmfit.models import QuadraticModel from haven import mono_ID_calibration @@ -87,7 +86,9 @@ def test_aligns_mono_energy(mono_motor, id_motor, ion_chamber, pitch2_motor): @pytest.mark.skip(reason="``haven.plans.align_motor`` is deprecated.") -def test_fitting_callback(mono_motor, id_motor, ion_chamber, pitch2_motor, event_loop, RE): +def test_fitting_callback( + mono_motor, id_motor, ion_chamber, pitch2_motor, event_loop, RE +): fit_model = MagicMock() plan = mono_ID_calibration( energies=[8000, 9000], energy_motor=mono_motor, fit_model=fit_model diff --git a/src/haven/tests/test_monochromator.py b/src/haven/tests/test_monochromator.py index c7b86783..701286ab 100644 --- a/src/haven/tests/test_monochromator.py +++ b/src/haven/tests/test_monochromator.py @@ -1,7 +1,3 @@ -import time - -import epics - from haven import Monochromator diff --git a/src/haven/tests/test_motor.py b/src/haven/tests/test_motor.py index f3f5b124..d2eafb38 100644 --- a/src/haven/tests/test_motor.py +++ b/src/haven/tests/test_motor.py @@ -1,5 +1,3 @@ -import epics - from haven.instrument import motor diff --git a/src/haven/tests/test_plans.py b/src/haven/tests/test_plans.py index b423c44e..05bef29b 100644 --- a/src/haven/tests/test_plans.py +++ b/src/haven/tests/test_plans.py @@ -4,14 +4,12 @@ """ -import unittest import warnings -import numpy as np -from ophyd import sim import pytest +from ophyd import sim -from haven import align_slits, energy_scan, xafs_scan, registry, KRange +from haven import align_slits def test_align_slits(RE): diff --git a/src/haven/tests/test_preprocessors.py b/src/haven/tests/test_preprocessors.py index d399106c..60ff8fc0 100644 --- a/src/haven/tests/test_preprocessors.py +++ b/src/haven/tests/test_preprocessors.py @@ -1,15 +1,12 @@ from unittest.mock import MagicMock -import pytest from bluesky import plans as bp from bluesky.callbacks import CallbackBase -from bluesky.simulators import summarize_plan -from ophyd.sim import det, motor, SynAxis, make_fake_device, instantiate_fake_device -import os +from ophyd.sim import SynAxis, det, instantiate_fake_device -from haven import plans, baseline_decorator, baseline_wrapper, run_engine -from haven.preprocessors import shutter_suspend_wrapper, shutter_suspend_decorator -from haven.instrument.aps import EpicsBssDevice, load_aps, ApsMachine +from haven import baseline_decorator, baseline_wrapper, run_engine +from haven.instrument.aps import EpicsBssDevice +from haven.preprocessors import shutter_suspend_decorator, shutter_suspend_wrapper def test_shutter_suspend_wrapper(aps, shutters, sim_registry): diff --git a/src/haven/tests/test_run_engine.py b/src/haven/tests/test_run_engine.py index 58a02066..84fae655 100644 --- a/src/haven/tests/test_run_engine.py +++ b/src/haven/tests/test_run_engine.py @@ -3,8 +3,8 @@ import databroker from bluesky import RunEngine -from haven.instrument.aps import load_aps from haven import run_engine +from haven.instrument.aps import load_aps def test_subscribers_garbage_collection(monkeypatch, sim_registry): diff --git a/src/haven/tests/test_save_motor_positions.py b/src/haven/tests/test_save_motor_positions.py index 613cfd89..dcadb19f 100644 --- a/src/haven/tests/test_save_motor_positions.py +++ b/src/haven/tests/test_save_motor_positions.py @@ -1,23 +1,21 @@ +import datetime as dt import logging -import os import time -import time_machine -import pytz -from zoneinfo import ZoneInfo -import datetime as dt from datetime import datetime +from zoneinfo import ZoneInfo import pytest -from ophyd.sim import motor1, SynAxis, make_fake_device -from ophyd import EpicsMotor, Signal, Component as Cpt +import time_machine +from ophyd import Component as Cpt +from ophyd import Signal +from ophyd.sim import SynAxis, motor1 + from haven import ( - save_motor_position, - registry, get_motor_position, + list_current_motor_positions, list_motor_positions, recall_motor_position, - list_current_motor_positions, - HavenMotor, + save_motor_position, ) log = logging.getLogger(__name__) diff --git a/src/haven/tests/test_scaler_triggering.py b/src/haven/tests/test_scaler_triggering.py index d6b41bb0..dc4274c3 100644 --- a/src/haven/tests/test_scaler_triggering.py +++ b/src/haven/tests/test_scaler_triggering.py @@ -10,7 +10,6 @@ import pytest from ophyd import Device - from haven.instrument.scaler_triggered import ScalerTriggered diff --git a/src/haven/tests/test_set_energy.py b/src/haven/tests/test_set_energy.py index ccac16a3..12593406 100644 --- a/src/haven/tests/test_set_energy.py +++ b/src/haven/tests/test_set_energy.py @@ -1,7 +1,7 @@ import pytest from ophyd.sim import motor, motor1, motor2 -from haven import set_energy, exceptions +from haven import exceptions, set_energy def test_plan_messages(): diff --git a/src/haven/tests/test_shutter.py b/src/haven/tests/test_shutter.py index f99888f1..fca9cd8d 100644 --- a/src/haven/tests/test_shutter.py +++ b/src/haven/tests/test_shutter.py @@ -1,6 +1,5 @@ -from unittest import mock -from haven.instrument import shutter from haven import registry +from haven.instrument import shutter def test_shutter(sim_registry, beamline_connected): diff --git a/src/haven/tests/test_stages.py b/src/haven/tests/test_stages.py index 401fd68c..e875e7bb 100644 --- a/src/haven/tests/test_stages.py +++ b/src/haven/tests/test_stages.py @@ -1,15 +1,9 @@ """Tests for a generic X-Y stage.""" -import time -from unittest import mock -from collections import OrderedDict import pytest -from ophyd.sim import instantiate_fake_device, make_fake_device -import numpy as np -from datetime import datetime -from haven import registry, exceptions +from haven import exceptions, registry from haven.instrument import stage diff --git a/src/haven/tests/test_xdi_writer.py b/src/haven/tests/test_xdi_writer.py index 900dfba7..2a8ea245 100644 --- a/src/haven/tests/test_xdi_writer.py +++ b/src/haven/tests/test_xdi_writer.py @@ -1,23 +1,22 @@ -import pytest -from unittest import TestCase, expectedFailure -from io import StringIO +import datetime as dt +import logging import os import time +from io import StringIO from pathlib import Path -import datetime as dt -import logging +from unittest import TestCase, expectedFailure + +import numpy as np +import pytest # from freezegun import freeze_time import pytz import time_machine from bluesky import RunEngine -from ophyd.sim import motor, SynGauss, SynAxis -import numpy as np from numpy import asarray as array +from ophyd.sim import SynAxis, SynGauss, motor - -from haven import XDIWriter, exceptions, energy_scan - +from haven import XDIWriter, energy_scan, exceptions fake_time = pytz.timezone("America/New_York").localize( dt.datetime(2022, 8, 19, 19, 10, 51) @@ -51,23 +50,31 @@ "num_points": 10, "plan_args": { "args": [ - "SynAxis(prefix='', name='energy', " - "read_attrs=['readback', 'setpoint'], " - "configuration_attrs=['velocity', 'acceleration'])", + ( + "SynAxis(prefix='', name='energy', " + "read_attrs=['readback', 'setpoint'], " + "configuration_attrs=['velocity', 'acceleration'])" + ), array([8300, 8310, 8320, 8330, 8340, 8350, 8360, 8370, 8380, 8390]), - "SynAxis(prefix='', name='exposure', " - "read_attrs=['readback', 'setpoint'], " - "configuration_attrs=['velocity', 'acceleration'])", + ( + "SynAxis(prefix='', name='exposure', " + "read_attrs=['readback', 'setpoint'], " + "configuration_attrs=['velocity', 'acceleration'])" + ), [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], ], "detectors": [ - "SynGauss(prefix='', name='I0', " - "read_attrs=['val'], configuration_attrs=['Imax', " - "'center', 'sigma', 'noise', 'noise_multiplier'])", - "SynGauss(prefix='', name='It', " - "read_attrs=['val'], configuration_attrs=['Imax', " - "'center', 'sigma', 'noise', " - "'noise_multiplier'])", + ( + "SynGauss(prefix='', name='I0', " + "read_attrs=['val'], configuration_attrs=['Imax', " + "'center', 'sigma', 'noise', 'noise_multiplier'])" + ), + ( + "SynGauss(prefix='', name='It', " + "read_attrs=['val'], configuration_attrs=['Imax', " + "'center', 'sigma', 'noise', " + "'noise_multiplier'])" + ), ], "per_step": "None", }, @@ -75,15 +82,19 @@ "plan_pattern": "inner_list_product", "plan_pattern_args": { "args": [ - "SynAxis(prefix='', name='energy', " - "read_attrs=['readback', 'setpoint'], " - "configuration_attrs=['velocity', " - "'acceleration'])", + ( + "SynAxis(prefix='', name='energy', " + "read_attrs=['readback', 'setpoint'], " + "configuration_attrs=['velocity', " + "'acceleration'])" + ), array([8300, 8310, 8320, 8330, 8340, 8350, 8360, 8370, 8380, 8390]), - "SynAxis(prefix='', name='exposure', " - "read_attrs=['readback', 'setpoint'], " - "configuration_attrs=['velocity', " - "'acceleration'])", + ( + "SynAxis(prefix='', name='exposure', " + "read_attrs=['readback', 'setpoint'], " + "configuration_attrs=['velocity', " + "'acceleration'])" + ), [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], ] }, diff --git a/src/haven/tests/test_xray_source.py b/src/haven/tests/test_xray_source.py index 8a1c84b0..03a65dcd 100644 --- a/src/haven/tests/test_xray_source.py +++ b/src/haven/tests/test_xray_source.py @@ -1,7 +1,4 @@ -from unittest import mock - from haven.instrument.xray_source import load_xray_sources -import haven def test_load_xray_sources(sim_registry, beamline_connected): diff --git a/src/haven/tests/test_xspress.py b/src/haven/tests/test_xspress.py index 3c4b2a53..dbb21bf9 100644 --- a/src/haven/tests/test_xspress.py +++ b/src/haven/tests/test_xspress.py @@ -1,6 +1,5 @@ import pytest -from ophyd.sim import make_fake_device -from ophyd.device import do_not_wait_for_lazy_connection + from haven.instrument.xspress import Xspress3Detector diff --git a/src/haven/typing.py b/src/haven/typing.py index 7e75e57a..d4c7c1d0 100644 --- a/src/haven/typing.py +++ b/src/haven/typing.py @@ -1,7 +1,6 @@ -from typing import Union, Sequence - -from ophyd import Device, Component, Signal +from typing import Sequence, Union +from ophyd import Component, Device, Signal Detector = Union[Device, Component, Signal, str] diff --git a/src/haven/xdi_writer.py b/src/haven/xdi_writer.py index eccbf64b..16f5deed 100644 --- a/src/haven/xdi_writer.py +++ b/src/haven/xdi_writer.py @@ -1,16 +1,15 @@ +import datetime as dt import logging -import warnings -import unicodedata import re -import datetime as dt +import unicodedata +import warnings from pathlib import Path -from typing import Sequence, Optional, Union +from typing import Optional, Sequence, Union from bluesky.callbacks import CallbackBase from . import exceptions - log = logging.getLogger(__name__) diff --git a/tests/conftest.py b/tests/conftest.py index 50f11dc6..345a1d6b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,292 +1,292 @@ -import os -import warnings -from pathlib import Path -from unittest.mock import MagicMock -from types import SimpleNamespace -from collections import OrderedDict -from subprocess import Popen, TimeoutExpired, PIPE -import subprocess -import shutil -import time -from unittest import mock -import asyncio - -import pytest - -import ophyd -from ophyd import DynamicDeviceComponent as DDC, Kind -from ophyd.sim import ( - instantiate_fake_device, - make_fake_device, - fake_device_cache, - FakeEpicsSignal, -) -from pydm.data_plugins import add_plugin - -import haven -from haven.simulated_ioc import simulated_ioc -from haven import load_config, registry -from haven._iconfig import beamline_connected as _beamline_connected -from haven.instrument.aerotech import AerotechFlyer, AerotechStage -from haven.instrument.aps import ApsMachine -from haven.instrument.shutter import Shutter -from haven.instrument.camera import AravisDetector -from haven.instrument.delay import EpicsSignalWithIO -from haven.instrument.dxp import DxpDetector, add_mcas as add_dxp_mcas -from haven.instrument.ion_chamber import IonChamber -from haven.instrument.xspress import Xspress3Detector, add_mcas as add_xspress_mcas -from firefly.application import FireflyApplication -from firefly.ophyd_plugin import OphydPlugin -from firefly.main_window import FireflyMainWindow - - -# IOC_SCOPE = "function" -IOC_SCOPE = "session" - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_undulator(request): - prefix = "ID255:" - pvs = dict(energy=f"{prefix}Energy.VAL") - return run_fake_ioc( - module_name="haven.tests.ioc_undulator", - name="Fake undulator IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["energy"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_camera(request): - prefix = "255idgigeA:" - pvs = dict( - cam_acquire=f"{prefix}cam1:Acquire", - cam_acquire_busy=f"{prefix}cam1:AcquireBusy", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_area_detector", - name="Fake IOC for a simulated machine vision camera", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["cam_acquire_busy"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_area_detector(request): - prefix = "255idSimDet:" - pvs = dict( - cam_acquire=f"{prefix}cam1:Acquire", - cam_acquire_busy=f"{prefix}cam1:AcquireBusy", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_area_detector", - name="Fake IOC for a simulated area detector", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["cam_acquire_busy"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_bss(request): - prefix = "255idc:bss:" - pvs = dict( - esaf_id=f"{prefix}esaf:id", - esaf_cycle=f"{prefix}esaf:cycle", - proposal_id=f"{prefix}proposal:id", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_apsbss", - name="Fake IOC for APS beamline scheduling system (BSS)", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["esaf_cycle"], - request=request, - ) - - -def run_fake_ioc( - module_name, - prefix: str, - request, - name="Fake IOC", - pvs=None, - pv_to_check: str = None, -): - if pvs is None: - pvs = {} - pytest.importorskip("caproto.tests.conftest") - from caproto.tests.conftest import run_example_ioc, poll_readiness - - process = run_example_ioc( - module_name=module_name, - request=request, - pv_to_check=None, - args=("--prefix", prefix, "--list-pvs", "-v"), - very_verbose=False, - ) - # Verify the IOC started - if pv_to_check is not None: - poll_timeout, poll_attempts = 1.0, 30 - poll_readiness( - pv_to_check, timeout=poll_timeout, attempts=poll_attempts, process=process - ) - return SimpleNamespace( - process=process, prefix=prefix, name=name, pvs=pvs, type="caproto" - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_scaler(request): - prefix = "255idVME:scaler1" - pvs = dict(calc=f"{prefix}_calc2.VAL") - return run_fake_ioc( - module_name="haven.tests.ioc_scaler", - name="Fake scaler IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["calc"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_ptc10(request): - prefix = "255idptc10:" - pvs = dict( - pid1_voltage=f"{prefix}5A:output", - pid1_voltage_rbv=f"{prefix}5A:output_RBV", - tc1_temperature=f"{prefix}2A:temperature", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_ptc10", - name="Fake PTC10 temperature controller IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["tc1_temperature"], - request=request, - ) - - -@pytest.fixture(scope="session") -def pydm_ophyd_plugin(): - return add_plugin(OphydPlugin) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_motor(request): - prefix = "255idVME:" - pvs = dict(m1=f"{prefix}m1", m2=f"{prefix}m2", m3=f"{prefix}m3", m4=f"{prefix}m4") - return run_fake_ioc( - module_name="haven.tests.ioc_motor", - name="Fake motor IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["m1"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_preamp(request): - prefix = "255idc:" - pvs = dict( - preamp1_sens_num=f"{prefix}SR01:sens_num", - preamp2_sens_num=f"{prefix}SR02:sens_num", - preamp3_sens_num=f"{prefix}SR03:sens_num", - preamp4_sens_num=f"{prefix}SR04:sens_num", - preamp1_sens_unit=f"{prefix}SR01:sens_unit", - preamp2_sens_unit=f"{prefix}SR02:sens_unit", - preamp3_sens_unit=f"{prefix}SR03:sens_unit", - preamp4_sens_unit=f"{prefix}SR04:sens_unit", - preamp1_offset_num=f"{prefix}SR01:offset_num", - preamp2_offset_num=f"{prefix}SR02:offset_num", - preamp3_offset_num=f"{prefix}SR03:offset_num", - preamp4_offset_num=f"{prefix}SR04:offset_num", - preamp1_offset_unit=f"{prefix}SR01:offset_unit", - preamp2_offset_unit=f"{prefix}SR02:offset_unit", - preamp3_offset_unit=f"{prefix}SR03:offset_unit", - preamp4_offset_unit=f"{prefix}SR04:offset_unit", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_preamp", - name="Fake preamp IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["preamp1_sens_num"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_simple(request): - prefix = "simple:" - pvs = dict( - A=f"{prefix}A", - B=f"{prefix}B", - C=f"{prefix}C", - ) - pv_to_check = pvs["A"] - return run_fake_ioc( - module_name="haven.tests.ioc_simple", - name="Fake simple IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pv_to_check, - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_mono(request): - prefix = "255idMono:" - pvs = dict( - bragg=f"{prefix}ACS:m3", - energy=f"{prefix}Energy", - id_tracking=f"{prefix}ID_tracking", - id_offset=f"{prefix}ID_offset", - ) - return run_fake_ioc( - module_name="haven.tests.ioc_mono", - name="Fake mono IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["energy"], - request=request, - ) - - -@pytest.fixture(scope=IOC_SCOPE) -def ioc_dxp(request): - prefix = "255idDXP:" - pvs = dict(acquiring=f"{prefix}Acquiring") - return run_fake_ioc( - module_name="haven.tests.ioc_dxp", - name="Fake DXP-based detector IOC", - prefix=prefix, - pvs=pvs, - pv_to_check=pvs["acquiring"], - request=request, - ) - - -# Simulated devices -@pytest.fixture() -def queue_app(ffapp): - """An application that is set up to interact (fakely) with the queue - server. - - """ - warnings.warn("queue_app is deprecated, just use ffapp instead.") - return ffapp - - -@pytest.fixture() -def sim_vortex(dxp): - warnings.warn("sim_vortex is deprecated, just use ``dxp`` instead.") - return dxp +# import os +# import warnings +# from pathlib import Path +# from unittest.mock import MagicMock +# from types import SimpleNamespace +# from collections import OrderedDict +# from subprocess import Popen, TimeoutExpired, PIPE +# import subprocess +# import shutil +# import time +# from unittest import mock +# import asyncio + +# import pytest + +# import ophyd +# from ophyd import DynamicDeviceComponent as DDC, Kind +# from ophyd.sim import ( +# instantiate_fake_device, +# make_fake_device, +# fake_device_cache, +# FakeEpicsSignal, +# ) +# from pydm.data_plugins import add_plugin + +# import haven +# from haven.simulated_ioc import simulated_ioc +# from haven import load_config, registry +# from haven._iconfig import beamline_connected as _beamline_connected +# from haven.instrument.aerotech import AerotechFlyer, AerotechStage +# from haven.instrument.aps import ApsMachine +# from haven.instrument.shutter import Shutter +# from haven.instrument.camera import AravisDetector +# from haven.instrument.delay import EpicsSignalWithIO +# from haven.instrument.dxp import DxpDetector, add_mcas as add_dxp_mcas +# from haven.instrument.ion_chamber import IonChamber +# from haven.instrument.xspress import Xspress3Detector, add_mcas as add_xspress_mcas +# from firefly.application import FireflyApplication +# from firefly.ophyd_plugin import OphydPlugin +# from firefly.main_window import FireflyMainWindow + + +# # IOC_SCOPE = "function" +# IOC_SCOPE = "session" + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_undulator(request): +# prefix = "ID255:" +# pvs = dict(energy=f"{prefix}Energy.VAL") +# return run_fake_ioc( +# module_name="haven.tests.ioc_undulator", +# name="Fake undulator IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["energy"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_camera(request): +# prefix = "255idgigeA:" +# pvs = dict( +# cam_acquire=f"{prefix}cam1:Acquire", +# cam_acquire_busy=f"{prefix}cam1:AcquireBusy", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_area_detector", +# name="Fake IOC for a simulated machine vision camera", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["cam_acquire_busy"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_area_detector(request): +# prefix = "255idSimDet:" +# pvs = dict( +# cam_acquire=f"{prefix}cam1:Acquire", +# cam_acquire_busy=f"{prefix}cam1:AcquireBusy", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_area_detector", +# name="Fake IOC for a simulated area detector", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["cam_acquire_busy"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_bss(request): +# prefix = "255idc:bss:" +# pvs = dict( +# esaf_id=f"{prefix}esaf:id", +# esaf_cycle=f"{prefix}esaf:cycle", +# proposal_id=f"{prefix}proposal:id", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_apsbss", +# name="Fake IOC for APS beamline scheduling system (BSS)", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["esaf_cycle"], +# request=request, +# ) + + +# def run_fake_ioc( +# module_name, +# prefix: str, +# request, +# name="Fake IOC", +# pvs=None, +# pv_to_check: str = None, +# ): +# if pvs is None: +# pvs = {} +# pytest.importorskip("caproto.tests.conftest") +# from caproto.tests.conftest import run_example_ioc, poll_readiness + +# process = run_example_ioc( +# module_name=module_name, +# request=request, +# pv_to_check=None, +# args=("--prefix", prefix, "--list-pvs", "-v"), +# very_verbose=False, +# ) +# # Verify the IOC started +# if pv_to_check is not None: +# poll_timeout, poll_attempts = 1.0, 30 +# poll_readiness( +# pv_to_check, timeout=poll_timeout, attempts=poll_attempts, process=process +# ) +# return SimpleNamespace( +# process=process, prefix=prefix, name=name, pvs=pvs, type="caproto" +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_scaler(request): +# prefix = "255idVME:scaler1" +# pvs = dict(calc=f"{prefix}_calc2.VAL") +# return run_fake_ioc( +# module_name="haven.tests.ioc_scaler", +# name="Fake scaler IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["calc"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_ptc10(request): +# prefix = "255idptc10:" +# pvs = dict( +# pid1_voltage=f"{prefix}5A:output", +# pid1_voltage_rbv=f"{prefix}5A:output_RBV", +# tc1_temperature=f"{prefix}2A:temperature", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_ptc10", +# name="Fake PTC10 temperature controller IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["tc1_temperature"], +# request=request, +# ) + + +# @pytest.fixture(scope="session") +# def pydm_ophyd_plugin(): +# return add_plugin(OphydPlugin) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_motor(request): +# prefix = "255idVME:" +# pvs = dict(m1=f"{prefix}m1", m2=f"{prefix}m2", m3=f"{prefix}m3", m4=f"{prefix}m4") +# return run_fake_ioc( +# module_name="haven.tests.ioc_motor", +# name="Fake motor IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["m1"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_preamp(request): +# prefix = "255idc:" +# pvs = dict( +# preamp1_sens_num=f"{prefix}SR01:sens_num", +# preamp2_sens_num=f"{prefix}SR02:sens_num", +# preamp3_sens_num=f"{prefix}SR03:sens_num", +# preamp4_sens_num=f"{prefix}SR04:sens_num", +# preamp1_sens_unit=f"{prefix}SR01:sens_unit", +# preamp2_sens_unit=f"{prefix}SR02:sens_unit", +# preamp3_sens_unit=f"{prefix}SR03:sens_unit", +# preamp4_sens_unit=f"{prefix}SR04:sens_unit", +# preamp1_offset_num=f"{prefix}SR01:offset_num", +# preamp2_offset_num=f"{prefix}SR02:offset_num", +# preamp3_offset_num=f"{prefix}SR03:offset_num", +# preamp4_offset_num=f"{prefix}SR04:offset_num", +# preamp1_offset_unit=f"{prefix}SR01:offset_unit", +# preamp2_offset_unit=f"{prefix}SR02:offset_unit", +# preamp3_offset_unit=f"{prefix}SR03:offset_unit", +# preamp4_offset_unit=f"{prefix}SR04:offset_unit", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_preamp", +# name="Fake preamp IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["preamp1_sens_num"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_simple(request): +# prefix = "simple:" +# pvs = dict( +# A=f"{prefix}A", +# B=f"{prefix}B", +# C=f"{prefix}C", +# ) +# pv_to_check = pvs["A"] +# return run_fake_ioc( +# module_name="haven.tests.ioc_simple", +# name="Fake simple IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pv_to_check, +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_mono(request): +# prefix = "255idMono:" +# pvs = dict( +# bragg=f"{prefix}ACS:m3", +# energy=f"{prefix}Energy", +# id_tracking=f"{prefix}ID_tracking", +# id_offset=f"{prefix}ID_offset", +# ) +# return run_fake_ioc( +# module_name="haven.tests.ioc_mono", +# name="Fake mono IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["energy"], +# request=request, +# ) + + +# @pytest.fixture(scope=IOC_SCOPE) +# def ioc_dxp(request): +# prefix = "255idDXP:" +# pvs = dict(acquiring=f"{prefix}Acquiring") +# return run_fake_ioc( +# module_name="haven.tests.ioc_dxp", +# name="Fake DXP-based detector IOC", +# prefix=prefix, +# pvs=pvs, +# pv_to_check=pvs["acquiring"], +# request=request, +# ) + + +# # Simulated devices +# @pytest.fixture() +# def queue_app(ffapp): +# """An application that is set up to interact (fakely) with the queue +# server. + +# """ +# warnings.warn("queue_app is deprecated, just use ffapp instead.") +# return ffapp + + +# @pytest.fixture() +# def sim_vortex(dxp): +# warnings.warn("sim_vortex is deprecated, just use ``dxp`` instead.") +# return dxp diff --git a/tests/test_simulated_ioc.py b/tests/test_simulated_ioc.py index a0551ece..f10deb88 100644 --- a/tests/test_simulated_ioc.py +++ b/tests/test_simulated_ioc.py @@ -1,13 +1,10 @@ import logging import time from pathlib import Path -import os import pytest from epics import caget, caput -from haven.simulated_ioc import simulated_ioc - log = logging.getLogger(__name__)