ophyd-async 0.3a4__tar.gz → 0.3a6__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.3a4 → ophyd_async-0.3a6}/.codecov.yml +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_release.yml +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/PKG-INFO +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/design-goals.rst +1 -1
- ophyd_async-0.3a6/docs/explanations/flyscanning.rst +29 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/_version.py +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/__init__.py +6 -1
- ophyd_async-0.3a6/src/ophyd_async/core/async_status.py +142 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/detector.py +23 -29
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/device.py +32 -11
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/flyer.py +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/mock_signal_backend.py +14 -15
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/mock_signal_utils.py +9 -13
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/signal.py +71 -21
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/utils.py +30 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/aravis.py +1 -5
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +6 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +1 -7
- ophyd_async-0.3a6/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +38 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +3 -2
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -2
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +9 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/demo/__init__.py +33 -34
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/motion/motor.py +47 -42
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/pvi/pvi.py +2 -2
- ophyd_async-0.3a6/src/ophyd_async/epics/signal/__init__.py +15 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/__init__.py +2 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/writers/_hdf_writer.py +4 -4
- ophyd_async-0.3a6/src/ophyd_async/plan_stubs/__init__.py +13 -0
- ophyd_async-0.3a6/src/ophyd_async/plan_stubs/ensure_connected.py +22 -0
- ophyd_async-0.3a6/src/ophyd_async/plan_stubs/fly.py +149 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/protocols.py +32 -2
- ophyd_async-0.3a6/src/ophyd_async/sim/demo/sim_motor.py +103 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/PKG-INFO +1 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/SOURCES.txt +5 -6
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_async_status.py +44 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_device.py +104 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_device_collector.py +4 -1
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_flyer.py +12 -12
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_mock_signal_backend.py +16 -5
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_signal.py +9 -0
- ophyd_async-0.3a6/tests/core/test_watchable_async_status.py +196 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_aravis.py +4 -52
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/demo/test_demo.py +27 -16
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/demo/test_demo_ad_sim_detector.py +28 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/motion/test_motor.py +81 -13
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_hdf_panda.py +4 -8
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_trigger.py +1 -2
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_writer.py +2 -2
- ophyd_async-0.3a4/tests/test_flyer_with_panda.py → ophyd_async-0.3a6/tests/plan_stubs/test_fly.py +157 -13
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/demo/test_sim_motor.py +4 -35
- ophyd_async-0.3a4/docs/explanations/flyscanning.rst +0 -63
- ophyd_async-0.3a4/docs/images/hardware-triggered-scan.png +0 -0
- ophyd_async-0.3a4/docs/images/outer-scan.png +0 -0
- ophyd_async-0.3a4/docs/images/simple-hardware-scan.png +0 -0
- ophyd_async-0.3a4/src/ophyd_async/core/async_status.py +0 -98
- ophyd_async-0.3a4/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +0 -156
- ophyd_async-0.3a4/src/ophyd_async/epics/signal/__init__.py +0 -8
- ophyd_async-0.3a4/src/ophyd_async/planstubs/__init__.py +0 -5
- ophyd_async-0.3a4/src/ophyd_async/planstubs/prepare_trigger_and_dets.py +0 -57
- ophyd_async-0.3a4/src/ophyd_async/sim/demo/sim_motor.py +0 -118
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.copier-answers.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/CONTRIBUTING.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/actions/install_requirements/action.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/dependabot.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/pages/index.html +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_check.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.gitignore +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.mailmap +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/Dockerfile +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/LICENSE +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/README.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/_templates/README +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/_templates/custom-class-template.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/_templates/custom-module-template.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/conf.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/examples/epics_demo.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/examples/foo_detector.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations/event-loop-choice.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/explanations.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/genindex.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/choose-interfaces-for-devices.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/compound-devices.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/make-a-simple-device.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/make-a-standard-detector.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to/write-tests-for-devices.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/how-to.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/images/bluesky_ophyd_logo.svg +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/images/ophyd_favicon.svg +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/index.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/reference/api.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/reference.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/tutorials/using-existing-devices.rst +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/docs/tutorials.md +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/pyproject.toml +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/setup.cfg +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/device_save_loader.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/signal_backend.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/soft_signal_backend.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/core/standard_readable.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/_backend/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/_backend/_aioca.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/_backend/_p4p.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/_backend/common.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/drivers/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/pilatus.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/utils.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/demo/mover.db +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/demo/sensor.db +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/pvi/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/epics/signal/signal.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/log.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_common_blocks.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_panda_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_table.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_trigger.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/_utils.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/writers/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/panda/writers/_panda_hdf_file.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/pattern_generator.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async/sim/sim_pattern_generator.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/entry_points.txt +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/requires.txt +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/conftest.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_device_save_loader.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_soft_signal_backend.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_standard_readable.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/core/test_utils.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/_backend/test_common.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_controllers.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_drivers.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_kinetix.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_pilatus.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_scans.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_single_trigger_det.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_utils.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_vimba.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/areadetector/test_writers.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/test_pvi.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/test_records.db +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/epics/test_signals.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/db/panda.db +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_panda_controller.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/panda/test_table.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/protocols/test_protocols.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/conftest.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/test_pattern_generator.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/test_sim_detector.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/test_sim_writer.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/sim/test_streaming_plan.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/test_cli.py +0 -0
- {ophyd_async-0.3a4 → ophyd_async-0.3a6}/tests/test_log.py +0 -0
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
- name: Create GitHub Release
|
|
24
24
|
# We pin to the SHA, not the tag, for security reasons.
|
|
25
25
|
# https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions
|
|
26
|
-
uses: softprops/action-gh-release@
|
|
26
|
+
uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5
|
|
27
27
|
with:
|
|
28
28
|
prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
|
|
29
29
|
files: "*"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3a6
|
|
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
|
|
@@ -32,7 +32,7 @@ Parity with Malcolm
|
|
|
32
32
|
|
|
33
33
|
Ophyd-async should provide the same building blocks for defining flyscans scans as malcolm_. It should support PandA and Zebra as timing masters by default, but also provide easy helpers for developers to write support for their own devices.
|
|
34
34
|
|
|
35
|
-
It should enable
|
|
35
|
+
It should enable motor trajectory scanning and multiple triggering rates based around a base rate, and pausing/resuming scans. Scans should be modelled using scanspec_, which serves as a universal language for defining trajectory and time-resolved scans, and converted to the underlying format of the given motion controller. It should also be possible to define an outer scan .
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
Improved Trajectory Calculation
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Flyscanning
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
See the documents in the [bluesky cookbook](http://blueskyproject.io/bluesky-cookbook/glossary/flyscanning.html)
|
|
5
|
+
|
|
6
|
+
Hardware
|
|
7
|
+
--------
|
|
8
|
+
|
|
9
|
+
Ophyd-async ships with support for Quantum Detectors' PandA_ and Zebra_ as triggering mechanisms.
|
|
10
|
+
|
|
11
|
+
These are very modular and can be used to trigger a variety of detectors and handle readback signals from a variety of sample control devices. See full specs for more information.
|
|
12
|
+
|
|
13
|
+
It is possible to write support for additional systems/devices.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Role of Ophyd-Async
|
|
17
|
+
-------------------
|
|
18
|
+
|
|
19
|
+
Bluesky supports devices that configure acquisition and then hand over control to an external system via the ``Flyer`` protocol.
|
|
20
|
+
|
|
21
|
+
Ophyd-async's job is to provide devices that implement ``Flyer`` and can:
|
|
22
|
+
|
|
23
|
+
- Configure all necessary hardware for a scan
|
|
24
|
+
- Kickoff a scan and monitor progress until complete
|
|
25
|
+
- Produce documents representing the progress of the scan
|
|
26
|
+
- Allow handing control back and forth to enable outer scanning
|
|
27
|
+
|
|
28
|
+
.. _PandA: https://quantumdetectors.com/products/pandabox/
|
|
29
|
+
.. _Zebra: https://quantumdetectors.com/products/zebra/
|
|
@@ -5,7 +5,7 @@ from ._providers import (
|
|
|
5
5
|
ShapeProvider,
|
|
6
6
|
StaticDirectoryProvider,
|
|
7
7
|
)
|
|
8
|
-
from .async_status import AsyncStatus
|
|
8
|
+
from .async_status import AsyncStatus, WatchableAsyncStatus
|
|
9
9
|
from .detector import (
|
|
10
10
|
DetectorControl,
|
|
11
11
|
DetectorTrigger,
|
|
@@ -57,6 +57,8 @@ from .soft_signal_backend import SoftSignalBackend
|
|
|
57
57
|
from .standard_readable import ConfigSignal, HintedSignal, StandardReadable
|
|
58
58
|
from .utils import (
|
|
59
59
|
DEFAULT_TIMEOUT,
|
|
60
|
+
CalculatableTimeout,
|
|
61
|
+
CalculateTimeout,
|
|
60
62
|
Callback,
|
|
61
63
|
NotConnected,
|
|
62
64
|
ReadingValueCallback,
|
|
@@ -96,6 +98,7 @@ __all__ = [
|
|
|
96
98
|
"set_mock_value",
|
|
97
99
|
"wait_for_value",
|
|
98
100
|
"AsyncStatus",
|
|
101
|
+
"WatchableAsyncStatus",
|
|
99
102
|
"DirectoryInfo",
|
|
100
103
|
"DirectoryProvider",
|
|
101
104
|
"NameProvider",
|
|
@@ -107,6 +110,8 @@ __all__ = [
|
|
|
107
110
|
"TriggerInfo",
|
|
108
111
|
"TriggerLogic",
|
|
109
112
|
"HardwareTriggeredFlyable",
|
|
113
|
+
"CalculateTimeout",
|
|
114
|
+
"CalculatableTimeout",
|
|
110
115
|
"DEFAULT_TIMEOUT",
|
|
111
116
|
"Callback",
|
|
112
117
|
"NotConnected",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Equivalent of bluesky.protocols.Status for asynchronous tasks."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import functools
|
|
5
|
+
import time
|
|
6
|
+
from dataclasses import asdict, replace
|
|
7
|
+
from typing import (
|
|
8
|
+
AsyncIterator,
|
|
9
|
+
Awaitable,
|
|
10
|
+
Callable,
|
|
11
|
+
Generic,
|
|
12
|
+
Type,
|
|
13
|
+
TypeVar,
|
|
14
|
+
cast,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
from bluesky.protocols import Status
|
|
18
|
+
|
|
19
|
+
from ..protocols import Watcher
|
|
20
|
+
from .utils import Callback, P, T, WatcherUpdate
|
|
21
|
+
|
|
22
|
+
AS = TypeVar("AS", bound="AsyncStatus")
|
|
23
|
+
WAS = TypeVar("WAS", bound="WatchableAsyncStatus")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class AsyncStatusBase(Status):
|
|
27
|
+
"""Convert asyncio awaitable to bluesky Status interface"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, awaitable: Awaitable):
|
|
30
|
+
if isinstance(awaitable, asyncio.Task):
|
|
31
|
+
self.task = awaitable
|
|
32
|
+
else:
|
|
33
|
+
self.task = asyncio.create_task(awaitable)
|
|
34
|
+
self.task.add_done_callback(self._run_callbacks)
|
|
35
|
+
self._callbacks: list[Callback[Status]] = []
|
|
36
|
+
|
|
37
|
+
def __await__(self):
|
|
38
|
+
return self.task.__await__()
|
|
39
|
+
|
|
40
|
+
def add_callback(self, callback: Callback[Status]):
|
|
41
|
+
if self.done:
|
|
42
|
+
callback(self)
|
|
43
|
+
else:
|
|
44
|
+
self._callbacks.append(callback)
|
|
45
|
+
|
|
46
|
+
def _run_callbacks(self, task: asyncio.Task):
|
|
47
|
+
for callback in self._callbacks:
|
|
48
|
+
callback(self)
|
|
49
|
+
|
|
50
|
+
def exception(self, timeout: float | None = 0.0) -> BaseException | None:
|
|
51
|
+
if timeout != 0.0:
|
|
52
|
+
raise ValueError(
|
|
53
|
+
"cannot honour any timeout other than 0 in an asynchronous function"
|
|
54
|
+
)
|
|
55
|
+
if self.task.done():
|
|
56
|
+
try:
|
|
57
|
+
return self.task.exception()
|
|
58
|
+
except asyncio.CancelledError as e:
|
|
59
|
+
return e
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def done(self) -> bool:
|
|
64
|
+
return self.task.done()
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def success(self) -> bool:
|
|
68
|
+
return (
|
|
69
|
+
self.task.done()
|
|
70
|
+
and not self.task.cancelled()
|
|
71
|
+
and self.task.exception() is None
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def __repr__(self) -> str:
|
|
75
|
+
if self.done:
|
|
76
|
+
if e := self.exception():
|
|
77
|
+
status = f"errored: {repr(e)}"
|
|
78
|
+
else:
|
|
79
|
+
status = "done"
|
|
80
|
+
else:
|
|
81
|
+
status = "pending"
|
|
82
|
+
return f"<{type(self).__name__}, task: {self.task.get_coro()}, {status}>"
|
|
83
|
+
|
|
84
|
+
__str__ = __repr__
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class AsyncStatus(AsyncStatusBase):
|
|
88
|
+
@classmethod
|
|
89
|
+
def wrap(cls: Type[AS], f: Callable[P, Awaitable]) -> Callable[P, AS]:
|
|
90
|
+
"""Wrap an async function in an AsyncStatus."""
|
|
91
|
+
|
|
92
|
+
@functools.wraps(f)
|
|
93
|
+
def wrap_f(*args: P.args, **kwargs: P.kwargs) -> AS:
|
|
94
|
+
return cls(f(*args, **kwargs))
|
|
95
|
+
|
|
96
|
+
# type is actually functools._Wrapped[P, Awaitable, P, AS]
|
|
97
|
+
# but functools._Wrapped is not necessarily available
|
|
98
|
+
return cast(Callable[P, AS], wrap_f)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class WatchableAsyncStatus(AsyncStatusBase, Generic[T]):
|
|
102
|
+
"""Convert AsyncIterator of WatcherUpdates to bluesky Status interface."""
|
|
103
|
+
|
|
104
|
+
def __init__(self, iterator: AsyncIterator[WatcherUpdate[T]]):
|
|
105
|
+
self._watchers: list[Watcher] = []
|
|
106
|
+
self._start = time.monotonic()
|
|
107
|
+
self._last_update: WatcherUpdate[T] | None = None
|
|
108
|
+
super().__init__(self._notify_watchers_from(iterator))
|
|
109
|
+
|
|
110
|
+
async def _notify_watchers_from(self, iterator: AsyncIterator[WatcherUpdate[T]]):
|
|
111
|
+
async for update in iterator:
|
|
112
|
+
self._last_update = (
|
|
113
|
+
update
|
|
114
|
+
if update.time_elapsed is not None
|
|
115
|
+
else replace(update, time_elapsed=time.monotonic() - self._start)
|
|
116
|
+
)
|
|
117
|
+
for watcher in self._watchers:
|
|
118
|
+
self._update_watcher(watcher, self._last_update)
|
|
119
|
+
|
|
120
|
+
def _update_watcher(self, watcher: Watcher, update: WatcherUpdate[T]):
|
|
121
|
+
vals = asdict(
|
|
122
|
+
update, dict_factory=lambda d: {k: v for k, v in d if v is not None}
|
|
123
|
+
)
|
|
124
|
+
watcher(**vals)
|
|
125
|
+
|
|
126
|
+
def watch(self, watcher: Watcher):
|
|
127
|
+
self._watchers.append(watcher)
|
|
128
|
+
if self._last_update:
|
|
129
|
+
self._update_watcher(watcher, self._last_update)
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def wrap(
|
|
133
|
+
cls: Type[WAS],
|
|
134
|
+
f: Callable[P, AsyncIterator[WatcherUpdate[T]]],
|
|
135
|
+
) -> Callable[P, WAS]:
|
|
136
|
+
"""Wrap an AsyncIterator in a WatchableAsyncStatus."""
|
|
137
|
+
|
|
138
|
+
@functools.wraps(f)
|
|
139
|
+
def wrap_f(*args: P.args, **kwargs: P.kwargs) -> WAS:
|
|
140
|
+
return cls(f(*args, **kwargs))
|
|
141
|
+
|
|
142
|
+
return cast(Callable[P, WAS], wrap_f)
|
|
@@ -31,9 +31,9 @@ from bluesky.protocols import (
|
|
|
31
31
|
|
|
32
32
|
from ophyd_async.protocols import AsyncConfigurable, AsyncReadable
|
|
33
33
|
|
|
34
|
-
from .async_status import AsyncStatus
|
|
34
|
+
from .async_status import AsyncStatus, WatchableAsyncStatus
|
|
35
35
|
from .device import Device
|
|
36
|
-
from .utils import DEFAULT_TIMEOUT, merge_gathered_dicts
|
|
36
|
+
from .utils import DEFAULT_TIMEOUT, WatcherUpdate, merge_gathered_dicts
|
|
37
37
|
|
|
38
38
|
T = TypeVar("T")
|
|
39
39
|
|
|
@@ -188,7 +188,7 @@ class StandardDetector(
|
|
|
188
188
|
self._trigger_info: Optional[TriggerInfo] = None
|
|
189
189
|
# For kickoff
|
|
190
190
|
self._watchers: List[Callable] = []
|
|
191
|
-
self._fly_status: Optional[
|
|
191
|
+
self._fly_status: Optional[WatchableAsyncStatus] = None
|
|
192
192
|
self._fly_start: float
|
|
193
193
|
|
|
194
194
|
self._intial_frame: int
|
|
@@ -292,43 +292,37 @@ class StandardDetector(
|
|
|
292
292
|
f"Detector {self.controller} needs at least {required}s deadtime, "
|
|
293
293
|
f"but trigger logic provides only {self._trigger_info.deadtime}s"
|
|
294
294
|
)
|
|
295
|
-
|
|
296
295
|
self._arm_status = await self.controller.arm(
|
|
297
296
|
num=self._trigger_info.num,
|
|
298
297
|
trigger=self._trigger_info.trigger,
|
|
299
298
|
exposure=self._trigger_info.livetime,
|
|
300
299
|
)
|
|
301
|
-
|
|
302
|
-
@AsyncStatus.wrap
|
|
303
|
-
async def kickoff(self) -> None:
|
|
304
|
-
self._fly_status = AsyncStatus(self._fly(), self._watchers)
|
|
305
300
|
self._fly_start = time.monotonic()
|
|
306
301
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
302
|
+
@AsyncStatus.wrap
|
|
303
|
+
async def kickoff(self):
|
|
304
|
+
if not self._arm_status:
|
|
305
|
+
raise Exception("Detector not armed!")
|
|
306
|
+
|
|
307
|
+
@WatchableAsyncStatus.wrap
|
|
308
|
+
async def complete(self):
|
|
309
|
+
assert self._arm_status, "Prepare not run"
|
|
310
|
+
assert self._trigger_info
|
|
311
311
|
async for index in self.writer.observe_indices_written(
|
|
312
312
|
self._frame_writing_timeout
|
|
313
313
|
):
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if index >= end_observation:
|
|
314
|
+
yield WatcherUpdate(
|
|
315
|
+
name=self.name,
|
|
316
|
+
current=index,
|
|
317
|
+
initial=self._initial_frame,
|
|
318
|
+
target=self._trigger_info.num,
|
|
319
|
+
unit="",
|
|
320
|
+
precision=0,
|
|
321
|
+
time_elapsed=time.monotonic() - self._fly_start,
|
|
322
|
+
)
|
|
323
|
+
if index >= self._trigger_info.num:
|
|
325
324
|
break
|
|
326
325
|
|
|
327
|
-
@AsyncStatus.wrap
|
|
328
|
-
async def complete(self) -> AsyncStatus:
|
|
329
|
-
assert self._fly_status, "Kickoff not run"
|
|
330
|
-
return await self._fly_status
|
|
331
|
-
|
|
332
326
|
async def describe_collect(self) -> Dict[str, DataKey]:
|
|
333
327
|
return self._describe
|
|
334
328
|
|
|
@@ -338,7 +332,7 @@ class StandardDetector(
|
|
|
338
332
|
# Collect stream datum documents for all indices written.
|
|
339
333
|
# The index is optional, and provided for fly scans, however this needs to be
|
|
340
334
|
# retrieved for step scans.
|
|
341
|
-
if
|
|
335
|
+
if index is None:
|
|
342
336
|
index = await self.writer.get_indices_written()
|
|
343
337
|
async for doc in self.writer.collect_stream_docs(index):
|
|
344
338
|
yield doc
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Base device"""
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import asyncio
|
|
5
4
|
import sys
|
|
6
5
|
from functools import cached_property
|
|
7
6
|
from logging import LoggerAdapter, getLogger
|
|
@@ -31,7 +30,10 @@ class Device(HasName):
|
|
|
31
30
|
|
|
32
31
|
_name: str = ""
|
|
33
32
|
#: The parent Device if it exists
|
|
34
|
-
parent: Optional[Device] = None
|
|
33
|
+
parent: Optional["Device"] = None
|
|
34
|
+
# None if connect hasn't started, a Task if it has
|
|
35
|
+
_connect_task: Optional[asyncio.Task] = None
|
|
36
|
+
_connect_mock_arg: bool = False
|
|
35
37
|
|
|
36
38
|
def __init__(self, name: str = "") -> None:
|
|
37
39
|
self.set_name(name)
|
|
@@ -47,7 +49,7 @@ class Device(HasName):
|
|
|
47
49
|
getLogger("ophyd_async.devices"), {"ophyd_async_device_name": self.name}
|
|
48
50
|
)
|
|
49
51
|
|
|
50
|
-
def children(self) -> Iterator[Tuple[str, Device]]:
|
|
52
|
+
def children(self) -> Iterator[Tuple[str, "Device"]]:
|
|
51
53
|
for attr_name, attr in self.__dict__.items():
|
|
52
54
|
if attr_name != "parent" and isinstance(attr, Device):
|
|
53
55
|
yield attr_name, attr
|
|
@@ -71,7 +73,12 @@ class Device(HasName):
|
|
|
71
73
|
child.set_name(child_name)
|
|
72
74
|
child.parent = self
|
|
73
75
|
|
|
74
|
-
async def connect(
|
|
76
|
+
async def connect(
|
|
77
|
+
self,
|
|
78
|
+
mock: bool = False,
|
|
79
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
80
|
+
force_reconnect: bool = False,
|
|
81
|
+
):
|
|
75
82
|
"""Connect self and all child Devices.
|
|
76
83
|
|
|
77
84
|
Contains a timeout that gets propagated to child.connect methods.
|
|
@@ -83,12 +90,26 @@ class Device(HasName):
|
|
|
83
90
|
timeout:
|
|
84
91
|
Time to wait before failing with a TimeoutError.
|
|
85
92
|
"""
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
# If previous connect with same args has started and not errored, can use it
|
|
94
|
+
can_use_previous_connect = (
|
|
95
|
+
self._connect_task
|
|
96
|
+
and not (self._connect_task.done() and self._connect_task.exception())
|
|
97
|
+
and self._connect_mock_arg == mock
|
|
98
|
+
)
|
|
99
|
+
if force_reconnect or not can_use_previous_connect:
|
|
100
|
+
# Kick off a connection
|
|
101
|
+
coros = {
|
|
102
|
+
name: child_device.connect(
|
|
103
|
+
mock, timeout=timeout, force_reconnect=force_reconnect
|
|
104
|
+
)
|
|
105
|
+
for name, child_device in self.children()
|
|
106
|
+
}
|
|
107
|
+
self._connect_task = asyncio.create_task(wait_for_connection(**coros))
|
|
108
|
+
self._connect_mock_arg = mock
|
|
109
|
+
|
|
110
|
+
assert self._connect_task, "Connect task not created, this shouldn't happen"
|
|
111
|
+
# Wait for it to complete
|
|
112
|
+
await self._connect_task
|
|
92
113
|
|
|
93
114
|
|
|
94
115
|
VT = TypeVar("VT", bound=Device)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
from functools import cached_property
|
|
2
3
|
from typing import Optional, Type
|
|
3
|
-
from unittest.mock import
|
|
4
|
+
from unittest.mock import Mock
|
|
4
5
|
|
|
5
6
|
from bluesky.protocols import Descriptor, Reading
|
|
6
7
|
|
|
@@ -36,51 +37,49 @@ class MockSignalBackend(SignalBackend):
|
|
|
36
37
|
else:
|
|
37
38
|
self.soft_backend = initial_backend
|
|
38
39
|
|
|
39
|
-
self.mock = MagicMock()
|
|
40
|
-
|
|
41
|
-
self.put_proceeds = asyncio.Event()
|
|
42
|
-
self.put_proceeds.set()
|
|
43
|
-
|
|
44
40
|
def source(self, name: str) -> str:
|
|
45
|
-
self.mock.source(name)
|
|
46
41
|
if self.initial_backend:
|
|
47
42
|
return f"mock+{self.initial_backend.source(name)}"
|
|
48
43
|
return f"mock+{name}"
|
|
49
44
|
|
|
50
45
|
async def connect(self, timeout: float = DEFAULT_TIMEOUT) -> None:
|
|
51
|
-
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
@cached_property
|
|
49
|
+
def put_mock(self) -> Mock:
|
|
50
|
+
return Mock(name="put")
|
|
51
|
+
|
|
52
|
+
@cached_property
|
|
53
|
+
def put_proceeds(self) -> asyncio.Event:
|
|
54
|
+
put_proceeds = asyncio.Event()
|
|
55
|
+
put_proceeds.set()
|
|
56
|
+
return put_proceeds
|
|
52
57
|
|
|
53
58
|
async def put(self, value: Optional[T], wait=True, timeout=None):
|
|
54
|
-
self.
|
|
59
|
+
self.put_mock(value, wait=wait, timeout=timeout)
|
|
55
60
|
await self.soft_backend.put(value, wait=wait, timeout=timeout)
|
|
56
61
|
|
|
57
62
|
if wait:
|
|
58
63
|
await asyncio.wait_for(self.put_proceeds.wait(), timeout=timeout)
|
|
59
64
|
|
|
60
65
|
def set_value(self, value: T):
|
|
61
|
-
self.mock.set_value(value)
|
|
62
66
|
self.soft_backend.set_value(value)
|
|
63
67
|
|
|
64
68
|
async def get_descriptor(self, source: str) -> Descriptor:
|
|
65
|
-
self.mock.get_descriptor(source)
|
|
66
69
|
return await self.soft_backend.get_descriptor(source)
|
|
67
70
|
|
|
68
71
|
async def get_reading(self) -> Reading:
|
|
69
|
-
self.mock.get_reading()
|
|
70
72
|
return await self.soft_backend.get_reading()
|
|
71
73
|
|
|
72
74
|
async def get_value(self) -> T:
|
|
73
|
-
self.mock.get_value()
|
|
74
75
|
return await self.soft_backend.get_value()
|
|
75
76
|
|
|
76
77
|
async def get_setpoint(self) -> T:
|
|
77
78
|
"""For a soft signal, the setpoint and readback values are the same."""
|
|
78
|
-
self.mock.get_setpoint()
|
|
79
79
|
return await self.soft_backend.get_setpoint()
|
|
80
80
|
|
|
81
81
|
async def get_datakey(self, source: str) -> Descriptor:
|
|
82
82
|
return await self.soft_backend.get_datakey(source)
|
|
83
83
|
|
|
84
84
|
def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
|
|
85
|
-
self.mock.set_callback(callback)
|
|
86
85
|
self.soft_backend.set_callback(callback)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from contextlib import asynccontextmanager, contextmanager
|
|
2
|
-
from typing import Any, Callable,
|
|
3
|
-
from unittest.mock import ANY
|
|
2
|
+
from typing import Any, Callable, Iterable, Iterator, List
|
|
3
|
+
from unittest.mock import ANY, Mock
|
|
4
4
|
|
|
5
5
|
from ophyd_async.core.signal import Signal
|
|
6
6
|
from ophyd_async.core.utils import T
|
|
@@ -43,12 +43,12 @@ async def mock_puts_blocked(*signals: List[Signal]):
|
|
|
43
43
|
|
|
44
44
|
def assert_mock_put_called_with(signal: Signal, value: Any, wait=ANY, timeout=ANY):
|
|
45
45
|
backend = _get_mock_signal_backend(signal)
|
|
46
|
-
backend.
|
|
46
|
+
backend.put_mock.assert_called_with(value, wait=wait, timeout=timeout)
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def reset_mock_put_calls(signal: Signal):
|
|
50
50
|
backend = _get_mock_signal_backend(signal)
|
|
51
|
-
backend.
|
|
51
|
+
backend.put_mock.reset_mock()
|
|
52
52
|
|
|
53
53
|
|
|
54
54
|
class _SetValuesIterator:
|
|
@@ -122,16 +122,12 @@ def set_mock_values(
|
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
@contextmanager
|
|
125
|
-
def _unset_side_effect_cm(
|
|
125
|
+
def _unset_side_effect_cm(put_mock: Mock):
|
|
126
126
|
yield
|
|
127
|
-
|
|
127
|
+
put_mock.side_effect = None
|
|
128
128
|
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
# ContextManager[None]
|
|
132
|
-
def callback_on_mock_put(
|
|
133
|
-
signal: Signal, callback: Callable[[T], None]
|
|
134
|
-
) -> Generator[None, None, None]:
|
|
130
|
+
def callback_on_mock_put(signal: Signal, callback: Callable[[T], None]):
|
|
135
131
|
"""For setting a callback when a backend is put to.
|
|
136
132
|
|
|
137
133
|
Can either be used in a context, with the callback being
|
|
@@ -145,5 +141,5 @@ def callback_on_mock_put(
|
|
|
145
141
|
The callback to call when the backend is put to during the context.
|
|
146
142
|
"""
|
|
147
143
|
backend = _get_mock_signal_backend(signal)
|
|
148
|
-
backend.
|
|
149
|
-
return _unset_side_effect_cm(backend.
|
|
144
|
+
backend.put_mock.side_effect = callback
|
|
145
|
+
return _unset_side_effect_cm(backend.put_mock)
|