ophyd-async 0.13.6__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.copier-answers.yml +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.devcontainer/devcontainer.json +21 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/CONTRIBUTING.md +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_test.yml +1 -13
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/ci.yml +4 -7
- ophyd_async-0.14.0/Dockerfile +25 -0
- {ophyd_async-0.13.6/src/ophyd_async.egg-info → ophyd_async-0.14.0}/PKG-INFO +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/conf.py +0 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials/writing-tests-for-devices.md +41 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/pyproject.toml +1 -1
- {ophyd_async-0.13.6/.github → ophyd_async-0.14.0}/renovate.json +5 -21
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/_version.py +3 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/__init__.py +28 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_device.py +92 -16
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_mock_signal_backend.py +7 -1
- {ophyd_async-0.13.6/src/ophyd_async/testing → ophyd_async-0.14.0/src/ophyd_async/core}/_mock_signal_utils.py +11 -14
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_signal.py +3 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_utils.py +0 -40
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/motor.py +55 -4
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/pmac/_pmac_io.py +10 -13
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/pmac/_pmac_trajectory.py +9 -10
- ophyd_async-0.14.0/src/ophyd_async/epics/pmac/_utils.py +210 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/__init__.py +0 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/_base_device.py +4 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/_counter.py +10 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/_mover.py +4 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/__init__.py +27 -17
- {ophyd_async-0.13.6 → ophyd_async-0.14.0/src/ophyd_async.egg-info}/PKG-INFO +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async.egg-info/SOURCES.txt +6 -5
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/conftest.py +160 -0
- ophyd_async-0.14.0/tests/system_tests/conftest.py +11 -0
- ophyd_async-0.14.0/tests/system_tests/epics/adsim/external_dependencies.sh +32 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/adsim/test_adsim_system.py +20 -4
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/signal/test_signals.py +2 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/tango/test_base_device.py +5 -4
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/tango/test_tango_signals.py +1 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_auto_init_devices.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_flyer.py +7 -10
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_mock_signal_backend.py +10 -12
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_observe.py +2 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_signal.py +34 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_cont_acq_detector.py +1 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_drivers.py +1 -4
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_scans.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_writers.py +2 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adkinetix/test_kinetix.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adpilatus/test_pilatus.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adsimdetector/test_sim.py +2 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/advimba/test_vimba.py +1 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/conftest.py +1 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/eiger/test_odin_io.py +3 -3
- ophyd_async-0.14.0/tests/unit_tests/epics/pmac/conftest.py +92 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/pmac/test_pmac_trajectory.py +5 -5
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/pmac/test_pmac_trajectory_generation.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/pmac/test_pmac_utils.py +40 -5
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/test_motor.py +226 -11
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/eiger/test_eiger_controller.py +2 -4
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/eiger/test_eiger_detector.py +8 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/jungfrau/test_controller.py +7 -5
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_hdf_panda.py +2 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_trigger.py +1 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_writer.py +2 -1
- ophyd_async-0.14.0/tests/unit_tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/plan_stubs/test_settings.py +1 -2
- ophyd_async-0.14.0/tests/unit_tests/sim/__init__.py +0 -0
- ophyd_async-0.13.6/Dockerfile +0 -10
- ophyd_async-0.13.6/src/ophyd_async/epics/pmac/_utils.py +0 -167
- ophyd_async-0.13.6/src/ophyd_async/tango/core/_tango_readable.py +0 -15
- ophyd_async-0.13.6/tests/system_tests/epics/adsim/start_iocs.sh +0 -14
- ophyd_async-0.13.6/tests/system_tests/epics/adsim/stop_iocs.sh +0 -14
- ophyd_async-0.13.6/tests/unit_tests/epics/pmac/conftest.py +0 -34
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.codecov.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/ISSUE_TEMPLATE/issue.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/codeql/codeql-config.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/pages/index.html +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_codeql.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.gitignore +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.gitleaks.toml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.gitmodules +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/.python-version +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/LICENSE +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/README.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/_static/custom.css +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0008-signal-types.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0010-docstring-format.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/0011-buffer-updates-camonitor.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/declarative-vs-procedural.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/design-goals.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/device-connection-strategies.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/devices-signals-backends.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/fly-scanning.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/plan-stubs.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/when-to-extend-movable.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations/where-device-logic.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/explanations.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/genindex.rst +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/choose-right-baseclass.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/derive-one-signal-from-others.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/implement-ad-detector.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/interact-with-signals.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/put-device-back.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to/store-and-retrieve.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/how-to.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/images/ophyd-async-logo.svg +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/images/ophyd-favicon.svg +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/index.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/reference.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials/implementing-detectors.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials/implementing-devices.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials/using-devices.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/docs/tutorials.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/setup.cfg +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/_docs_parser.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_derived_signal.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_derived_signal_backend.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_device_filler.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_enums.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_flyer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_hdf_dataset.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_log.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_protocol.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_readable.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_settings.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_signal_backend.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_status.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_table.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/core/_yaml_settings.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adandor/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adandor/_andor.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_core_logic.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adcore/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/advimba/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_aioca.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_epics_device.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_p4p.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_signal.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/core/_util.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/__main__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/_ioc.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/_motor.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/_stage.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/motor.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/point_detector.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/odin/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/odin/_odin_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/pmac/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/pmac/_pmac_trajectory_generation.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/signal.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/testing/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/testing/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/testing/test_records.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/core.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/eiger/_eiger.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/eiger/_eiger_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/jungfrau/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/jungfrau/_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/jungfrau/_jungfrau.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/jungfrau/_signals.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/jungfrau/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_block.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_control.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_table.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_fly.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_panda.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_settings.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/py.typed +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/__main__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_blob_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_motor.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_pattern_generator.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_point_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/sim/_stage.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/_converters.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/_signal.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/core/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/testing/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/tango/testing/_test_config.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/_assert.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/_one_of_everything.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/_single_derived.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async.egg-info/requires.txt +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/README.md +0 -0
- {ophyd_async-0.13.6/tests/unit_tests/fastcs/jungfrau → ophyd_async-0.14.0/tests/system_tests}/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/adsim/baseline.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/eiger/README.md +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/eiger/test_eiger_system.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/signal/test_yaml_save_ca.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/epics/signal/test_yaml_save_pva.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/fastcs/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/tango/conftest.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/tango/context_subprocess.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/tango/test_tango_transport.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/system_tests/test_tutorials.py +0 -0
- {ophyd_async-0.13.6/tests/unit_tests/sim → ophyd_async-0.14.0/tests/unit_tests}/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_device.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_log.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_multi_derived_signal.py +2 -2
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_protocol.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_providers.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_readable.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_single_derived_signal.py +1 -1
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_soft_signal_backend.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_status.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_subset_enum.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_table.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adandor/test_andor.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adaravis/test_aravis.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_detectors.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_plugins.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/adcore/test_single_trigger.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/demo/test_epics_demo.py +3 -3
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/pmac/test_pmac_io.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/pvi/test_pvi.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/signal/test_common.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/epics/test_areadetector_subclass_naming.py +0 -0
- /ophyd_async-0.13.6/tests/unit_tests/plan_stubs/test_fly.py → /ophyd_async-0.14.0/tests/unit_tests/fastcs/jungfrau/__init__.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/jungfrau/test_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/db/panda.db +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_panda_connect_mock.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_panda_control.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/fastcs/panda/test_seq_table.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/plan_stubs/test_ensure_connected.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/plan_stubs/test_setup.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/sim/test_sim_blob_detector.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/sim/test_sim_motor.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/test_branching.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/test_cli.py +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/test_data/test_yaml_config_save.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/tests/unit_tests/test_data/test_yaml_save.yaml +0 -0
- {ophyd_async-0.13.6 → ophyd_async-0.14.0}/uv.lock +0 -0
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"UV_PROJECT_ENVIRONMENT": "/cache/venv-for${localWorkspaceFolder}",
|
|
17
17
|
// Do the equivalent of "activate" the venv so we don't have to "uv run" everything
|
|
18
18
|
"VIRTUAL_ENV": "/cache/venv-for${localWorkspaceFolder}",
|
|
19
|
-
"PATH": "/cache/venv-for${localWorkspaceFolder}/bin:${containerEnv:PATH}"
|
|
19
|
+
"PATH": "/cache/venv-for${localWorkspaceFolder}/bin:${containerEnv:PATH}",
|
|
20
|
+
// Help external service fixtures match docker compose working directory with the host
|
|
21
|
+
"EXAMPLE_SERVICES_PATH": "${localWorkspaceFolder}/example-services"
|
|
20
22
|
},
|
|
21
23
|
"customizations": {
|
|
22
24
|
"vscode": {
|
|
@@ -32,6 +34,9 @@
|
|
|
32
34
|
"python.terminal.shellIntegration.enabled": false,
|
|
33
35
|
"python.testing.unittestEnabled": false,
|
|
34
36
|
"python.testing.pytestEnabled": true,
|
|
37
|
+
"python.testing.pytestArgs": [
|
|
38
|
+
"tests"
|
|
39
|
+
],
|
|
35
40
|
"editor.formatOnSave": true,
|
|
36
41
|
"editor.codeActionsOnSave": {
|
|
37
42
|
"source.organizeImports": "explicit"
|
|
@@ -58,7 +63,9 @@
|
|
|
58
63
|
// Allow the container to access the host X11 display and EPICS CA
|
|
59
64
|
"--net=host",
|
|
60
65
|
// Make sure SELinux does not disable with access to host filesystems like tmp
|
|
61
|
-
"--security-opt=label=disable"
|
|
66
|
+
"--security-opt=label=disable",
|
|
67
|
+
// add the docker socket environment variable to the container
|
|
68
|
+
"-e=DOCKER_HOST=${localEnv:DOCKER_HOST}"
|
|
62
69
|
],
|
|
63
70
|
"mounts": [
|
|
64
71
|
// Mount in the user terminal config folder so it can be edited
|
|
@@ -72,6 +79,18 @@
|
|
|
72
79
|
"source": "devcontainer-shared-cache",
|
|
73
80
|
"target": "/cache",
|
|
74
81
|
"type": "volume"
|
|
82
|
+
},
|
|
83
|
+
// Match host external services file paths (internal docker starts them on the host)
|
|
84
|
+
{
|
|
85
|
+
"source": "${localWorkspaceFolder}/example-services",
|
|
86
|
+
"target": "${localWorkspaceFolder}/example-services",
|
|
87
|
+
"type": "bind"
|
|
88
|
+
},
|
|
89
|
+
// Mount the user sockets folder
|
|
90
|
+
{
|
|
91
|
+
"source": "${localEnv:XDG_RUNTIME_DIR}",
|
|
92
|
+
"target": "${localEnv:XDG_RUNTIME_DIR}",
|
|
93
|
+
"type": "bind"
|
|
75
94
|
}
|
|
76
95
|
],
|
|
77
96
|
// Mount the parent as /workspaces so we can pip install peers as editable
|
|
@@ -24,4 +24,4 @@ It is recommended that developers use a [vscode devcontainer](https://code.visua
|
|
|
24
24
|
|
|
25
25
|
This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects.
|
|
26
26
|
|
|
27
|
-
For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.
|
|
27
|
+
For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.0a5/how-to.html).
|
|
@@ -13,10 +13,6 @@ on:
|
|
|
13
13
|
type: string
|
|
14
14
|
description: The path to look for tests
|
|
15
15
|
required: true
|
|
16
|
-
needs-services:
|
|
17
|
-
type: boolean
|
|
18
|
-
description: Whether to start external services
|
|
19
|
-
required: true
|
|
20
16
|
secrets:
|
|
21
17
|
CODECOV_TOKEN:
|
|
22
18
|
required: true
|
|
@@ -32,6 +28,7 @@ jobs:
|
|
|
32
28
|
|
|
33
29
|
env:
|
|
34
30
|
COVERAGE_PROCESS_START: .coveragerc
|
|
31
|
+
EXAMPLE_SERVICES_PATH: ./example-services
|
|
35
32
|
|
|
36
33
|
steps:
|
|
37
34
|
- name: Checkout repository (with submodules)
|
|
@@ -49,15 +46,6 @@ jobs:
|
|
|
49
46
|
- name: Install uv
|
|
50
47
|
uses: astral-sh/setup-uv@v7
|
|
51
48
|
|
|
52
|
-
- if: inputs.needs-services && inputs.runs-on != 'windows-latest'
|
|
53
|
-
name: Run docker compose
|
|
54
|
-
uses: hoverkraft-tech/compose-action@v2.4.1
|
|
55
|
-
with:
|
|
56
|
-
compose-file: "./example-services/compose.yaml"
|
|
57
|
-
services: |
|
|
58
|
-
bl01t-di-cam-01
|
|
59
|
-
ca-gateway
|
|
60
|
-
|
|
61
49
|
- name: Run tests win
|
|
62
50
|
if: inputs.runs-on == 'windows-latest'
|
|
63
51
|
run: uv run --locked tox -e tests -- --timeout=10 ${{ inputs.tests-path}}
|
|
@@ -19,23 +19,20 @@ jobs:
|
|
|
19
19
|
matrix:
|
|
20
20
|
runs-on: ["ubuntu-latest", "windows-latest"] # can add macos-latest
|
|
21
21
|
python-version: ["3.11", "3.12", "3.13"]
|
|
22
|
-
|
|
23
|
-
- tests-path: "tests/unit_tests"
|
|
24
|
-
needs-services: false
|
|
25
|
-
- tests-path: "tests/system_tests"
|
|
26
|
-
needs-services: true
|
|
22
|
+
tests-path: ["", "tests/system_tests"]
|
|
27
23
|
fail-fast: false
|
|
28
24
|
uses: ./.github/workflows/_test.yml
|
|
29
25
|
with:
|
|
30
26
|
runs-on: ${{ matrix.runs-on }}
|
|
31
27
|
python-version: ${{ matrix.python-version }}
|
|
32
|
-
tests-path: ${{ matrix.
|
|
33
|
-
needs-services: ${{ matrix.test-config.needs-services }}
|
|
28
|
+
tests-path: ${{ matrix.tests-path }}
|
|
34
29
|
secrets:
|
|
35
30
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
36
31
|
|
|
37
32
|
docs:
|
|
38
33
|
uses: ./.github/workflows/_docs.yml
|
|
34
|
+
permissions:
|
|
35
|
+
contents: write
|
|
39
36
|
|
|
40
37
|
dist:
|
|
41
38
|
uses: ./.github/workflows/_dist.yml
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# The devcontainer should use the developer target and run as root with podman
|
|
2
|
+
# or docker with user namespaces.
|
|
3
|
+
FROM ghcr.io/diamondlightsource/ubuntu-devcontainer:noble AS developer
|
|
4
|
+
|
|
5
|
+
ENV DOCKER=docker-28.5.1
|
|
6
|
+
ENV DOCKER_COMPOSE_RELEASE_TAG=v2.40.3
|
|
7
|
+
|
|
8
|
+
# Add any system dependencies for the developer/build environment here
|
|
9
|
+
RUN apt-get update -y && apt-get install -y --no-install-recommends \
|
|
10
|
+
graphviz \
|
|
11
|
+
libxcb-cursor0 \
|
|
12
|
+
qt6-base-dev \
|
|
13
|
+
curl \
|
|
14
|
+
&& apt-get dist-clean
|
|
15
|
+
|
|
16
|
+
# install the docker ce cli binary
|
|
17
|
+
RUN curl -O https://download.docker.com/linux/static/stable/x86_64/${DOCKER}.tgz && \
|
|
18
|
+
tar xvf ${DOCKER}.tgz && \
|
|
19
|
+
cp docker/docker /usr/bin && \
|
|
20
|
+
rm -r ${DOCKER}.tgz docker
|
|
21
|
+
|
|
22
|
+
# install docker-compose plugin
|
|
23
|
+
RUN mkdir -p /usr/libexec/docker/cli-plugins/ && \
|
|
24
|
+
curl -SL https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_RELEASE_TAG}/docker-compose-linux-x86_64 -o /usr/libexec/docker/cli-plugins/docker-compose && \
|
|
25
|
+
chmod +x /usr/libexec/docker/cli-plugins/docker-compose
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.0
|
|
4
4
|
Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
|
|
5
5
|
Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -206,7 +206,6 @@ intersphinx_mapping = {
|
|
|
206
206
|
"bluesky": ("https://blueskyproject.io/bluesky/main", None),
|
|
207
207
|
"scanspec": ("https://blueskyproject.io/scanspec/main", None),
|
|
208
208
|
"numpy": ("https://numpy.org/devdocs/", None),
|
|
209
|
-
"databroker": ("https://blueskyproject.io/databroker/", None),
|
|
210
209
|
"event-model": ("https://blueskyproject.io/event-model/main", None),
|
|
211
210
|
"pytest": ("https://docs.pytest.org/en/stable/", None),
|
|
212
211
|
}
|
|
@@ -87,6 +87,47 @@ There are a few other things we may wish to do in tests:
|
|
|
87
87
|
- [](#set_mock_put_proceeds) to block or unblock `Signal.set(..., wait=True)` from completing
|
|
88
88
|
- [](#mock_puts_blocked) a context manager that blocks put proceeds at the start, and unblocks at the end
|
|
89
89
|
|
|
90
|
+
### Automatic mock behavior injection
|
|
91
|
+
|
|
92
|
+
If you find yourself repeatedly using [](#callback_on_mock_put) to set up the same mock behavior for a Device type across many tests, you can define a [](#DeviceMock) subclass to automatically inject that behavior when the Device is connected in mock mode. This is especially useful for defining standard mock behavior alongside your Device definitions, making it easier to switch between hardware and mock modes.
|
|
93
|
+
|
|
94
|
+
For example, if you have a device that needs automatic mock behavior, you can define:
|
|
95
|
+
|
|
96
|
+
```{literalinclude} ../../src/ophyd_async/epics/motor.py
|
|
97
|
+
:language: python
|
|
98
|
+
:pyobject: InstantMotorMock
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Then decorate the original class with [](#default_mock_class) so it is automatically used when connected in mock mode:
|
|
102
|
+
|
|
103
|
+
```{literalinclude} ../../src/ophyd_async/epics/motor.py
|
|
104
|
+
:language: python
|
|
105
|
+
:start-at: default_mock_class(
|
|
106
|
+
:end-at: class Motor
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Now whenever a Motor is connected in mock mode using [](#init_devices)`(mock=True)`, it will automatically use `InstantMotorMock` and have this behavior:
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
async with init_devices(mock=True):
|
|
113
|
+
motor = Motor("BLxxI-MO-TABLE-01:X")
|
|
114
|
+
|
|
115
|
+
# No manual callback setup needed - the mock behavior is already active
|
|
116
|
+
await motor.user_setpoint.set(50.0)
|
|
117
|
+
assert await motor.user_readback.get_value() == 50.0
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
You can still override the automatic mock for specific tests by passing an explicit [](#DeviceMock) instance:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Use a plain DeviceMock without the automatic behavior
|
|
124
|
+
custom_mock = DeviceMock()
|
|
125
|
+
motor = Motor("TEST:MOTOR")
|
|
126
|
+
await motor.connect(mock=custom_mock)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This approach keeps your mock logic close to your Device definition, reduces duplication across tests, and makes it easier to maintain consistent mock behavior.
|
|
130
|
+
|
|
90
131
|
## Tests that execute a bluesky plan
|
|
91
132
|
|
|
92
133
|
If we need to check that our Device performs correctly within a plan that calls multiple verbs, it is best to test it under an actual RunEngine. This allows you to check that when the verbs are called in the order that they are in the plan, the correct behavior occurs.
|
|
@@ -96,7 +96,7 @@ addopts = """
|
|
|
96
96
|
--ignore=docs/examples --ignore=src/ophyd_async/epics/signal.py
|
|
97
97
|
"""
|
|
98
98
|
# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings
|
|
99
|
-
filterwarnings = "error"
|
|
99
|
+
filterwarnings = ["error"]
|
|
100
100
|
# Doctest python code in docs, python code in src docstrings, test functions in tests
|
|
101
101
|
testpaths = "docs src tests/unit_tests"
|
|
102
102
|
log_format = "%(asctime)s,%(msecs)03d %(levelname)s (%(threadName)s) %(message)s"
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"lockFileMaintenance": {
|
|
7
7
|
"description": "Keep uv.lock up to date, merging if tests pass",
|
|
8
8
|
"enabled": true,
|
|
9
|
-
"automerge": true
|
|
9
|
+
"automerge": true
|
|
10
10
|
},
|
|
11
11
|
"packageRules": [
|
|
12
12
|
{
|
|
@@ -20,34 +20,18 @@
|
|
|
20
20
|
"description": "Disable github actions that are managed by python-copier-template",
|
|
21
21
|
"matchPackageNames": [
|
|
22
22
|
"actions/checkout",
|
|
23
|
-
"actions/download-artifact",
|
|
24
|
-
"actions/setup-python",
|
|
25
|
-
"actions/upload-artifact",
|
|
26
23
|
"astral-sh/setup-uv",
|
|
24
|
+
"actions/upload-artifact",
|
|
25
|
+
"actions/download-artifact",
|
|
26
|
+
"softprops/action-gh-release",
|
|
27
27
|
"codecov/codecov-action",
|
|
28
|
-
"docker/build-push-action",
|
|
29
|
-
"docker/login-action",
|
|
30
|
-
"docker/metadata-action",
|
|
31
|
-
"docker/setup-buildx-action",
|
|
32
|
-
"peaceiris/actions-gh-pages",
|
|
33
28
|
"pypa/gh-action-pypi-publish",
|
|
34
|
-
"
|
|
29
|
+
"peaceiris/actions-gh-pages"
|
|
35
30
|
],
|
|
36
31
|
"matchManagers": [
|
|
37
32
|
"github-actions"
|
|
38
33
|
],
|
|
39
34
|
"enabled": false
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"description": "Group non-major github action updates",
|
|
43
|
-
"groupName": "GitHub Actions",
|
|
44
|
-
"matchUpdateTypes": [
|
|
45
|
-
"patch",
|
|
46
|
-
"minor"
|
|
47
|
-
],
|
|
48
|
-
"matchManagers": [
|
|
49
|
-
"github-actions"
|
|
50
|
-
]
|
|
51
35
|
}
|
|
52
36
|
]
|
|
53
37
|
}
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.14.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 14, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g3da44d6fb'
|
|
@@ -14,7 +14,15 @@ from ._detector import (
|
|
|
14
14
|
StandardDetector,
|
|
15
15
|
TriggerInfo,
|
|
16
16
|
)
|
|
17
|
-
from ._device import
|
|
17
|
+
from ._device import (
|
|
18
|
+
Device,
|
|
19
|
+
DeviceConnector,
|
|
20
|
+
DeviceMock,
|
|
21
|
+
DeviceVector,
|
|
22
|
+
LazyMock,
|
|
23
|
+
default_mock_class,
|
|
24
|
+
init_devices,
|
|
25
|
+
)
|
|
18
26
|
from ._device_filler import DeviceFiller
|
|
19
27
|
from ._enums import (
|
|
20
28
|
EnabledDisabled,
|
|
@@ -27,6 +35,15 @@ from ._flyer import FlyerController, FlyMotorInfo, StandardFlyer
|
|
|
27
35
|
from ._hdf_dataset import HDFDatasetDescription, HDFDocumentComposer
|
|
28
36
|
from ._log import config_ophyd_async_logging
|
|
29
37
|
from ._mock_signal_backend import MockSignalBackend
|
|
38
|
+
from ._mock_signal_utils import (
|
|
39
|
+
callback_on_mock_put,
|
|
40
|
+
get_mock,
|
|
41
|
+
get_mock_put,
|
|
42
|
+
mock_puts_blocked,
|
|
43
|
+
set_mock_put_proceeds,
|
|
44
|
+
set_mock_value,
|
|
45
|
+
set_mock_values,
|
|
46
|
+
)
|
|
30
47
|
from ._protocol import AsyncConfigurable, AsyncReadable, AsyncStageable, Watcher
|
|
31
48
|
from ._providers import (
|
|
32
49
|
AutoIncrementFilenameProvider,
|
|
@@ -87,7 +104,6 @@ from ._utils import (
|
|
|
87
104
|
Callback,
|
|
88
105
|
ConfinedModel,
|
|
89
106
|
EnumTypes,
|
|
90
|
-
LazyMock,
|
|
91
107
|
NotConnectedError,
|
|
92
108
|
Reference,
|
|
93
109
|
StrictEnum,
|
|
@@ -166,8 +182,18 @@ __all__ = [
|
|
|
166
182
|
"soft_signal_r_and_setter",
|
|
167
183
|
"soft_signal_rw",
|
|
168
184
|
# Mock signal
|
|
185
|
+
"DeviceMock",
|
|
169
186
|
"LazyMock",
|
|
170
187
|
"MockSignalBackend",
|
|
188
|
+
"default_mock_class",
|
|
189
|
+
# Mocking utilities
|
|
190
|
+
"get_mock",
|
|
191
|
+
"set_mock_value",
|
|
192
|
+
"set_mock_values",
|
|
193
|
+
"get_mock_put",
|
|
194
|
+
"callback_on_mock_put",
|
|
195
|
+
"mock_puts_blocked",
|
|
196
|
+
"set_mock_put_proceeds",
|
|
171
197
|
# Signal utilities
|
|
172
198
|
"observe_value",
|
|
173
199
|
"observe_signals_value",
|
|
@@ -5,19 +5,71 @@ import sys
|
|
|
5
5
|
from collections.abc import Awaitable, Callable, Iterator, Mapping, MutableMapping
|
|
6
6
|
from functools import cached_property
|
|
7
7
|
from logging import LoggerAdapter, getLogger
|
|
8
|
-
from typing import Any, TypeVar
|
|
8
|
+
from typing import Any, Generic, TypeVar
|
|
9
|
+
from unittest.mock import Mock
|
|
9
10
|
|
|
10
11
|
from bluesky.protocols import HasName
|
|
11
12
|
from bluesky.run_engine import call_in_bluesky_event_loop, in_bluesky_event_loop
|
|
12
13
|
|
|
13
14
|
from ._utils import (
|
|
14
15
|
DEFAULT_TIMEOUT,
|
|
15
|
-
LazyMock,
|
|
16
16
|
NotConnectedError,
|
|
17
17
|
error_if_none,
|
|
18
18
|
wait_for_connection,
|
|
19
19
|
)
|
|
20
20
|
|
|
21
|
+
DeviceT = TypeVar("DeviceT", bound="Device")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DeviceMock(Generic[DeviceT]):
|
|
25
|
+
"""A lazily created Mock to be used when connecting in mock mode.
|
|
26
|
+
|
|
27
|
+
Creating Mocks is reasonably expensive when each Device (and Signal)
|
|
28
|
+
requires its own, and the tree is only used when ``Signal.set()`` is
|
|
29
|
+
called. This class allows a tree of lazily connected Mocks to be
|
|
30
|
+
constructed so that when the leaf is created, so are its parents.
|
|
31
|
+
Any calls to the child are then accessible from the parent mock.
|
|
32
|
+
|
|
33
|
+
Subclasses can override the `connect()` method to inject custom logic
|
|
34
|
+
when mock devices are connected.
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
>>> parent = DeviceMock()
|
|
38
|
+
>>> child = DeviceMock("child", parent)
|
|
39
|
+
>>> child_mock = child()
|
|
40
|
+
>>> child_mock() # doctest: +ELLIPSIS
|
|
41
|
+
<Mock name='mock.child()' id='...'>
|
|
42
|
+
>>> parent_mock = parent()
|
|
43
|
+
>>> parent_mock.mock_calls
|
|
44
|
+
[call.child()]
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self, name: str = "", parent: DeviceMock | None = None) -> None:
|
|
50
|
+
self.name = name
|
|
51
|
+
self.parent = parent
|
|
52
|
+
self._mock: Mock | None = None
|
|
53
|
+
|
|
54
|
+
def __call__(self) -> Mock:
|
|
55
|
+
if self._mock is None:
|
|
56
|
+
self._mock = Mock(spec=object)
|
|
57
|
+
if self.parent is not None:
|
|
58
|
+
self.parent().attach_mock(self._mock, self.name)
|
|
59
|
+
return self._mock
|
|
60
|
+
|
|
61
|
+
async def connect(self, device: DeviceT) -> None:
|
|
62
|
+
"""Will be called when the device is connected in mock mode.
|
|
63
|
+
|
|
64
|
+
This allows mock values to be set and callbacks to be added
|
|
65
|
+
to the mock device so it behaves more like the real device.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Keep LazyMock as an alias for backwards compatibility
|
|
70
|
+
# Remove for ophyd-async 1.0
|
|
71
|
+
LazyMock = DeviceMock
|
|
72
|
+
|
|
21
73
|
|
|
22
74
|
class DeviceConnector:
|
|
23
75
|
"""Defines how a `Device` should be connected and type hints processed."""
|
|
@@ -40,7 +92,7 @@ class DeviceConnector:
|
|
|
40
92
|
during `__init__`.
|
|
41
93
|
"""
|
|
42
94
|
|
|
43
|
-
async def connect_mock(self, device: Device, mock:
|
|
95
|
+
async def connect_mock(self, device: Device, mock: DeviceMock):
|
|
44
96
|
"""Use during [](#Device.connect) with `mock=True`.
|
|
45
97
|
|
|
46
98
|
This is called when there is no cached connect done in `mock=True`
|
|
@@ -50,12 +102,16 @@ class DeviceConnector:
|
|
|
50
102
|
exceptions: dict[str, Exception] = {}
|
|
51
103
|
for name, child_device in device.children():
|
|
52
104
|
try:
|
|
53
|
-
|
|
105
|
+
child_mock_class = child_device._mock_class # noqa: SLF001
|
|
106
|
+
await child_device.connect(mock=child_mock_class(name, mock))
|
|
54
107
|
except Exception as exc:
|
|
55
108
|
exceptions[name] = exc
|
|
56
109
|
if exceptions:
|
|
57
110
|
raise NotConnectedError.with_other_exceptions_logged(exceptions)
|
|
58
111
|
|
|
112
|
+
# Call the DeviceMock's connect method to inject custom logic
|
|
113
|
+
await mock.connect(device)
|
|
114
|
+
|
|
59
115
|
async def connect_real(self, device: Device, timeout: float, force_reconnect: bool):
|
|
60
116
|
"""Use during [](#Device.connect) with `mock=False`.
|
|
61
117
|
|
|
@@ -82,8 +138,10 @@ class Device(HasName):
|
|
|
82
138
|
_name: str = ""
|
|
83
139
|
# None if connect hasn't started, a Task if it has
|
|
84
140
|
_connect_task: asyncio.Task | None = None
|
|
141
|
+
# The mock class to be used if we connect in mock mode
|
|
142
|
+
_mock_class: type[DeviceMock] = DeviceMock
|
|
85
143
|
# The mock if we have connected in mock mode
|
|
86
|
-
_mock:
|
|
144
|
+
_mock: DeviceMock | None = None
|
|
87
145
|
# The separator to use when making child names
|
|
88
146
|
_child_name_separator: str = "-"
|
|
89
147
|
|
|
@@ -163,7 +221,7 @@ class Device(HasName):
|
|
|
163
221
|
|
|
164
222
|
async def connect(
|
|
165
223
|
self,
|
|
166
|
-
mock: bool |
|
|
224
|
+
mock: bool | DeviceMock = False,
|
|
167
225
|
timeout: float = DEFAULT_TIMEOUT,
|
|
168
226
|
force_reconnect: bool = False,
|
|
169
227
|
) -> None:
|
|
@@ -175,25 +233,26 @@ class Device(HasName):
|
|
|
175
233
|
|
|
176
234
|
:param mock:
|
|
177
235
|
If True then use [](#MockSignalBackend) for all Signals. If passed a
|
|
178
|
-
[](#
|
|
179
|
-
otherwise create one
|
|
236
|
+
[](#DeviceMock) then pass this down for use within the Signals,
|
|
237
|
+
otherwise create one using the registered default mock for this device
|
|
238
|
+
type, or a plain [](#DeviceMock) if no default is registered.
|
|
180
239
|
:param timeout: Time to wait before failing with a TimeoutError.
|
|
181
240
|
:param force_reconnect:
|
|
182
241
|
If True, force a reconnect even if the last connect succeeded.
|
|
183
242
|
"""
|
|
184
|
-
connector = error_if_none(
|
|
243
|
+
connector: DeviceConnector = error_if_none(
|
|
185
244
|
getattr(self, "_connector", None),
|
|
186
245
|
f"{self}: doesn't have attribute `_connector`,"
|
|
187
246
|
f" did you call `super().__init__` in your `__init__` method?",
|
|
188
247
|
)
|
|
189
248
|
if mock:
|
|
190
249
|
# Always connect in mock mode serially
|
|
191
|
-
if isinstance(mock,
|
|
192
|
-
# Use the
|
|
250
|
+
if isinstance(mock, DeviceMock):
|
|
251
|
+
# Use the user supplied mock
|
|
193
252
|
self._mock = mock
|
|
194
253
|
elif not self._mock:
|
|
195
|
-
# Make
|
|
196
|
-
self._mock =
|
|
254
|
+
# Make a new mock of the registered type
|
|
255
|
+
self._mock = self._mock_class()
|
|
197
256
|
await connector.connect_mock(self, self._mock)
|
|
198
257
|
else:
|
|
199
258
|
# Try to cache the connect in real mode
|
|
@@ -223,9 +282,6 @@ _not_device_attrs = {
|
|
|
223
282
|
}
|
|
224
283
|
|
|
225
284
|
|
|
226
|
-
DeviceT = TypeVar("DeviceT", bound=Device)
|
|
227
|
-
|
|
228
|
-
|
|
229
285
|
class DeviceVector(MutableMapping[int, DeviceT], Device):
|
|
230
286
|
"""Defines a dictionary of Device children with arbitrary integer keys.
|
|
231
287
|
|
|
@@ -396,3 +452,23 @@ def init_devices(
|
|
|
396
452
|
await wait_for_connection(**coros)
|
|
397
453
|
|
|
398
454
|
return DeviceProcessor(process_devices)
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def default_mock_class(
|
|
458
|
+
mock_cls: type[DeviceMock],
|
|
459
|
+
) -> Callable[[type[DeviceT]], type[DeviceT]]:
|
|
460
|
+
"""Register a DeviceMock subclass as the default mock for a Device class.
|
|
461
|
+
|
|
462
|
+
This decorator allows automatic injection of mock logic when devices are
|
|
463
|
+
connected in mock mode. The decorated DeviceMock class should override
|
|
464
|
+
the `connect()` method to define custom mock behavior.
|
|
465
|
+
|
|
466
|
+
:param mock_cls: A DeviceMock subclass to register.
|
|
467
|
+
:returns: A decorator that registers the mock class for a Device subclass.
|
|
468
|
+
"""
|
|
469
|
+
|
|
470
|
+
def wrapper(device_cls: type[DeviceT]) -> type[DeviceT]:
|
|
471
|
+
device_cls._mock_class = mock_cls # noqa: SLF001
|
|
472
|
+
return device_cls
|
|
473
|
+
|
|
474
|
+
return wrapper
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
from collections.abc import Callable
|
|
3
5
|
from functools import cached_property
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
from unittest.mock import AsyncMock
|
|
5
8
|
|
|
6
9
|
from bluesky.protocols import Reading
|
|
@@ -9,7 +12,10 @@ from event_model import DataKey
|
|
|
9
12
|
from ._derived_signal_backend import DerivedSignalBackend
|
|
10
13
|
from ._signal_backend import SignalBackend, SignalDatatypeT
|
|
11
14
|
from ._soft_signal_backend import SoftSignalBackend
|
|
12
|
-
from ._utils import Callback
|
|
15
|
+
from ._utils import Callback
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from ._device import LazyMock
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
class MockSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
@@ -2,15 +2,10 @@ from collections.abc import Awaitable, Callable, Iterable, Iterator
|
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
from unittest.mock import AsyncMock, Mock
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Signal,
|
|
10
|
-
SignalConnector,
|
|
11
|
-
SignalDatatypeT,
|
|
12
|
-
SignalR,
|
|
13
|
-
)
|
|
5
|
+
from ._device import Device, DeviceMock
|
|
6
|
+
from ._mock_signal_backend import MockSignalBackend
|
|
7
|
+
from ._signal import Signal, SignalConnector, SignalR
|
|
8
|
+
from ._signal_backend import SignalDatatypeT
|
|
14
9
|
|
|
15
10
|
|
|
16
11
|
def get_mock(device: Device | Signal) -> Mock:
|
|
@@ -19,16 +14,18 @@ def get_mock(device: Device | Signal) -> Mock:
|
|
|
19
14
|
The device must have been connected in mock mode.
|
|
20
15
|
"""
|
|
21
16
|
mock = device._mock # noqa: SLF001
|
|
22
|
-
|
|
17
|
+
if not isinstance(mock, DeviceMock):
|
|
18
|
+
msg = f"Device {device} not connected in mock mode"
|
|
19
|
+
raise RuntimeError(msg)
|
|
23
20
|
return mock()
|
|
24
21
|
|
|
25
22
|
|
|
26
23
|
def _get_mock_signal_backend(signal: Signal) -> MockSignalBackend:
|
|
27
24
|
connector = signal._connector # noqa: SLF001
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
if not isinstance(connector, SignalConnector):
|
|
26
|
+
raise TypeError(f"Expected Signal, got {signal}")
|
|
27
|
+
if not isinstance(connector.backend, MockSignalBackend):
|
|
28
|
+
raise RuntimeError(f"Signal {signal} not connected in mock mode")
|
|
32
29
|
return connector.backend
|
|
33
30
|
|
|
34
31
|
|
|
@@ -19,7 +19,7 @@ from bluesky.protocols import (
|
|
|
19
19
|
from event_model import DataKey
|
|
20
20
|
from stamina import retry_context
|
|
21
21
|
|
|
22
|
-
from ._device import Device, DeviceConnector
|
|
22
|
+
from ._device import Device, DeviceConnector, LazyMock
|
|
23
23
|
from ._mock_signal_backend import MockSignalBackend
|
|
24
24
|
from ._protocol import AsyncReadable, AsyncStageable
|
|
25
25
|
from ._signal_backend import SignalBackend, SignalDatatypeT, SignalDatatypeV
|
|
@@ -30,7 +30,6 @@ from ._utils import (
|
|
|
30
30
|
DEFAULT_TIMEOUT,
|
|
31
31
|
CalculatableTimeout,
|
|
32
32
|
Callback,
|
|
33
|
-
LazyMock,
|
|
34
33
|
T,
|
|
35
34
|
error_if_none,
|
|
36
35
|
)
|
|
@@ -639,9 +638,10 @@ async def set_and_wait_for_other_value(
|
|
|
639
638
|
if wait_for_set_completion:
|
|
640
639
|
await status
|
|
641
640
|
except TimeoutError as exc:
|
|
641
|
+
matcher_name = getattr(matcher, "__name__", f"<{type(matcher).__name__}>")
|
|
642
642
|
raise TimeoutError(
|
|
643
643
|
f"{match_signal.name} value didn't match value from"
|
|
644
|
-
f" {
|
|
644
|
+
f" {matcher_name}() in {timeout}s"
|
|
645
645
|
) from exc
|
|
646
646
|
|
|
647
647
|
return status
|