ophyd-async 0.3.2__tar.gz → 0.3.4a1__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.3.2 → ophyd_async-0.3.4a1}/PKG-INFO +1 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/_version.py +2 -2
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/__init__.py +47 -44
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/signal_backend.py +47 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/soft_signal_backend.py +29 -12
- ophyd_async-0.3.4a1/src/ophyd_async/epics/_backend/common.py +62 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +4 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/__init__.py +2 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +32 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +5 -3
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/motion/motor.py +0 -2
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/PKG-INFO +1 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/SOURCES.txt +1 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_soft_signal_backend.py +1 -1
- ophyd_async-0.3.4a1/tests/core/test_subset_enum.py +90 -0
- ophyd_async-0.3.4a1/tests/epics/areadetector/test_drivers.py +96 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_pilatus.py +8 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/demo/test_demo.py +1 -1
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/test_signals.py +27 -7
- ophyd_async-0.3.2/src/ophyd_async/epics/_backend/common.py +0 -48
- ophyd_async-0.3.2/tests/epics/areadetector/test_drivers.py +0 -47
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.codecov.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.copier-answers.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/CONTRIBUTING.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/actions/install_requirements/action.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/dependabot.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/pages/index.html +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_check.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.gitignore +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.mailmap +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/Dockerfile +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/LICENSE +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/README.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/_templates/README +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/_templates/custom-class-template.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/_templates/custom-module-template.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/conf.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/examples/epics_demo.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/examples/foo_detector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/design-goals.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/event-loop-choice.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations/flyscanning.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/explanations.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/genindex.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/choose-interfaces-for-devices.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/compound-devices.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/make-a-simple-device.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/make-a-standard-detector.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to/write-tests-for-devices.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/how-to.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/images/bluesky_ophyd_logo.svg +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/images/ophyd_favicon.svg +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/index.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/reference/api.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/reference.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/tutorials/using-existing-devices.rst +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/docs/tutorials.md +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/pyproject.toml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/setup.cfg +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/async_status.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/detector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/device.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/device_save_loader.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/flyer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/mock_signal_backend.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/mock_signal_utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/signal.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/standard_readable.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/core/utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/_backend/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/_backend/_aioca.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/_backend/_p4p.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/aravis.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/pilatus.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/demo/mover.db +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/demo/sensor.db +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/pvi/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/pvi/pvi.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/signal/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/signal/signal.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/log.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_common_blocks.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_panda_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_table.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_trigger.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/_utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/writers/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/writers/_hdf_writer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/panda/writers/_panda_hdf_file.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/plan_stubs/ensure_connected.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/plan_stubs/fly.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/protocols.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/demo/sim_motor.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/pattern_generator.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/sim/sim_pattern_generator.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/entry_points.txt +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/requires.txt +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/conftest.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_async_status.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_device.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_device_collector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_device_save_loader.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_flyer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_mock_signal_backend.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_signal.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_standard_readable.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/_backend/test_common.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_aravis.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_controllers.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_kinetix.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_scans.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_single_trigger_det.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_vimba.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/areadetector/test_writers.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/demo/test_demo_ad_sim_detector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/motion/test_motor.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/test_pvi.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/epics/test_records.db +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/db/panda.db +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_hdf_panda.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_panda_controller.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_table.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_trigger.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/panda/test_writer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/protocols/test_protocols.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/conftest.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/demo/test_sim_motor.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/test_pattern_generator.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/test_sim_detector.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/test_sim_writer.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/sim/test_streaming_plan.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/test_cli.py +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/test_data/test_yaml_save.yml +0 -0
- {ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/tests/test_log.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4a1
|
|
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
|
|
@@ -50,7 +50,7 @@ from .signal import (
|
|
|
50
50
|
soft_signal_rw,
|
|
51
51
|
wait_for_value,
|
|
52
52
|
)
|
|
53
|
-
from .signal_backend import SignalBackend
|
|
53
|
+
from .signal_backend import RuntimeSubsetEnum, SignalBackend, SubsetEnum
|
|
54
54
|
from .soft_signal_backend import SoftSignalBackend
|
|
55
55
|
from .standard_readable import ConfigSignal, HintedSignal, StandardReadable
|
|
56
56
|
from .utils import (
|
|
@@ -68,66 +68,69 @@ from .utils import (
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
__all__ = [
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"SoftSignalBackend",
|
|
71
|
+
"AsyncStatus",
|
|
72
|
+
"CalculatableTimeout",
|
|
73
|
+
"CalculateTimeout",
|
|
74
|
+
"Callback",
|
|
75
|
+
"ConfigSignal",
|
|
76
|
+
"DEFAULT_TIMEOUT",
|
|
78
77
|
"DetectorControl",
|
|
79
|
-
"MockSignalBackend",
|
|
80
78
|
"DetectorTrigger",
|
|
81
79
|
"DetectorWriter",
|
|
82
|
-
"StandardDetector",
|
|
83
80
|
"Device",
|
|
84
81
|
"DeviceCollector",
|
|
85
82
|
"DeviceVector",
|
|
86
|
-
"Signal",
|
|
87
|
-
"SignalR",
|
|
88
|
-
"SignalW",
|
|
89
|
-
"SignalRW",
|
|
90
|
-
"SignalX",
|
|
91
|
-
"soft_signal_r_and_setter",
|
|
92
|
-
"soft_signal_rw",
|
|
93
|
-
"observe_value",
|
|
94
|
-
"set_and_wait_for_value",
|
|
95
|
-
"set_mock_put_proceeds",
|
|
96
|
-
"set_mock_value",
|
|
97
|
-
"wait_for_value",
|
|
98
|
-
"AsyncStatus",
|
|
99
|
-
"WatchableAsyncStatus",
|
|
100
83
|
"DirectoryInfo",
|
|
101
84
|
"DirectoryProvider",
|
|
85
|
+
"HardwareTriggeredFlyable",
|
|
86
|
+
"HintedSignal",
|
|
87
|
+
"MockSignalBackend",
|
|
102
88
|
"NameProvider",
|
|
89
|
+
"NotConnected",
|
|
90
|
+
"ReadingValueCallback",
|
|
91
|
+
"RuntimeSubsetEnum",
|
|
92
|
+
"SubsetEnum",
|
|
103
93
|
"ShapeProvider",
|
|
104
|
-
"
|
|
94
|
+
"Signal",
|
|
95
|
+
"SignalBackend",
|
|
96
|
+
"SignalR",
|
|
97
|
+
"SignalRW",
|
|
98
|
+
"SignalW",
|
|
99
|
+
"SignalX",
|
|
100
|
+
"SoftSignalBackend",
|
|
101
|
+
"StandardDetector",
|
|
105
102
|
"StandardReadable",
|
|
106
|
-
"
|
|
107
|
-
"
|
|
103
|
+
"StaticDirectoryProvider",
|
|
104
|
+
"T",
|
|
108
105
|
"TriggerInfo",
|
|
109
106
|
"TriggerLogic",
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"T",
|
|
107
|
+
"WatchableAsyncStatus",
|
|
108
|
+
"assert_configuration",
|
|
109
|
+
"assert_emitted",
|
|
110
|
+
"assert_mock_put_called_with",
|
|
111
|
+
"assert_reading",
|
|
112
|
+
"assert_value",
|
|
113
|
+
"callback_on_mock_put",
|
|
118
114
|
"get_dtype",
|
|
119
|
-
"
|
|
120
|
-
"merge_gathered_dicts",
|
|
121
|
-
"wait_for_connection",
|
|
115
|
+
"get_mock_put",
|
|
122
116
|
"get_signal_values",
|
|
117
|
+
"get_unique",
|
|
118
|
+
"load_device",
|
|
123
119
|
"load_from_yaml",
|
|
120
|
+
"merge_gathered_dicts",
|
|
121
|
+
"mock_puts_blocked",
|
|
122
|
+
"observe_value",
|
|
123
|
+
"reset_mock_put_calls",
|
|
124
|
+
"save_device",
|
|
124
125
|
"save_to_yaml",
|
|
126
|
+
"set_and_wait_for_value",
|
|
127
|
+
"set_mock_put_proceeds",
|
|
128
|
+
"set_mock_value",
|
|
129
|
+
"set_mock_values",
|
|
125
130
|
"set_signal_values",
|
|
131
|
+
"soft_signal_r_and_setter",
|
|
132
|
+
"soft_signal_rw",
|
|
133
|
+
"wait_for_connection",
|
|
134
|
+
"wait_for_value",
|
|
126
135
|
"walk_rw_signals",
|
|
127
|
-
"load_device",
|
|
128
|
-
"save_device",
|
|
129
|
-
"assert_reading",
|
|
130
|
-
"assert_value",
|
|
131
|
-
"assert_configuration",
|
|
132
|
-
"assert_emitted",
|
|
133
136
|
]
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import (
|
|
3
|
+
TYPE_CHECKING,
|
|
4
|
+
ClassVar,
|
|
5
|
+
Generic,
|
|
6
|
+
Literal,
|
|
7
|
+
Optional,
|
|
8
|
+
Tuple,
|
|
9
|
+
Type,
|
|
10
|
+
)
|
|
3
11
|
|
|
4
12
|
from bluesky.protocols import DataKey, Reading
|
|
5
13
|
|
|
@@ -45,3 +53,41 @@ class SignalBackend(Generic[T]):
|
|
|
45
53
|
@abstractmethod
|
|
46
54
|
def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
|
|
47
55
|
"""Observe changes to the current value, timestamp and severity"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class _RuntimeSubsetEnumMeta(type):
|
|
59
|
+
def __str__(cls):
|
|
60
|
+
if hasattr(cls, "choices"):
|
|
61
|
+
return f"SubsetEnum{list(cls.choices)}"
|
|
62
|
+
return "SubsetEnum"
|
|
63
|
+
|
|
64
|
+
def __getitem__(cls, _choices):
|
|
65
|
+
if isinstance(_choices, str):
|
|
66
|
+
_choices = (_choices,)
|
|
67
|
+
else:
|
|
68
|
+
if not isinstance(_choices, tuple) or not all(
|
|
69
|
+
isinstance(c, str) for c in _choices
|
|
70
|
+
):
|
|
71
|
+
raise TypeError(
|
|
72
|
+
"Choices must be a str or a tuple of str, " f"not {type(_choices)}."
|
|
73
|
+
)
|
|
74
|
+
if len(set(_choices)) != len(_choices):
|
|
75
|
+
raise TypeError("Duplicate elements in runtime enum choices.")
|
|
76
|
+
|
|
77
|
+
class _RuntimeSubsetEnum(cls):
|
|
78
|
+
choices = _choices
|
|
79
|
+
|
|
80
|
+
return _RuntimeSubsetEnum
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class RuntimeSubsetEnum(metaclass=_RuntimeSubsetEnumMeta):
|
|
84
|
+
choices: ClassVar[Tuple[str, ...]]
|
|
85
|
+
|
|
86
|
+
def __init__(self):
|
|
87
|
+
raise RuntimeError("SubsetEnum cannot be instantiated")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if TYPE_CHECKING:
|
|
91
|
+
SubsetEnum = Literal
|
|
92
|
+
else:
|
|
93
|
+
SubsetEnum = RuntimeSubsetEnum
|
|
@@ -3,14 +3,23 @@ from __future__ import annotations
|
|
|
3
3
|
import inspect
|
|
4
4
|
import time
|
|
5
5
|
from collections import abc
|
|
6
|
-
from dataclasses import dataclass
|
|
7
6
|
from enum import Enum
|
|
8
|
-
from typing import
|
|
7
|
+
from typing import (
|
|
8
|
+
Dict,
|
|
9
|
+
Generic,
|
|
10
|
+
Optional,
|
|
11
|
+
Tuple,
|
|
12
|
+
Type,
|
|
13
|
+
TypedDict,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
get_origin,
|
|
17
|
+
)
|
|
9
18
|
|
|
10
19
|
import numpy as np
|
|
11
20
|
from bluesky.protocols import DataKey, Dtype, Reading
|
|
12
21
|
|
|
13
|
-
from .signal_backend import SignalBackend
|
|
22
|
+
from .signal_backend import RuntimeSubsetEnum, SignalBackend
|
|
14
23
|
from .utils import DEFAULT_TIMEOUT, ReadingValueCallback, T, get_dtype
|
|
15
24
|
|
|
16
25
|
primitive_dtypes: Dict[type, Dtype] = {
|
|
@@ -74,23 +83,27 @@ class SoftArrayConverter(SoftConverter):
|
|
|
74
83
|
return cast(T, datatype(shape=0)) # type: ignore
|
|
75
84
|
|
|
76
85
|
|
|
77
|
-
@dataclass
|
|
78
86
|
class SoftEnumConverter(SoftConverter):
|
|
79
|
-
|
|
87
|
+
choices: Tuple[str, ...]
|
|
80
88
|
|
|
81
|
-
def
|
|
89
|
+
def __init__(self, datatype: Union[RuntimeSubsetEnum, Enum]):
|
|
90
|
+
if issubclass(datatype, Enum):
|
|
91
|
+
self.choices = tuple(v.value for v in datatype)
|
|
92
|
+
else:
|
|
93
|
+
self.choices = datatype.choices
|
|
94
|
+
|
|
95
|
+
def write_value(self, value: Union[Enum, str]) -> str:
|
|
82
96
|
if isinstance(value, Enum):
|
|
97
|
+
return value.value
|
|
98
|
+
else: # Runtime enum
|
|
83
99
|
return value
|
|
84
|
-
else:
|
|
85
|
-
return self.enum_class(value)
|
|
86
100
|
|
|
87
101
|
def get_datakey(self, source: str, value, **metadata) -> DataKey:
|
|
88
|
-
choices = [e.value for e in self.enum_class]
|
|
89
102
|
return {
|
|
90
103
|
"source": source,
|
|
91
104
|
"dtype": "string",
|
|
92
105
|
"shape": [],
|
|
93
|
-
"choices": choices,
|
|
106
|
+
"choices": self.choices,
|
|
94
107
|
**metadata,
|
|
95
108
|
}
|
|
96
109
|
|
|
@@ -98,13 +111,17 @@ class SoftEnumConverter(SoftConverter):
|
|
|
98
111
|
if datatype is None:
|
|
99
112
|
return cast(T, None)
|
|
100
113
|
|
|
101
|
-
|
|
114
|
+
if issubclass(datatype, Enum):
|
|
115
|
+
return cast(T, list(datatype.__members__.values())[0]) # type: ignore
|
|
116
|
+
return cast(T, self.choices[0])
|
|
102
117
|
|
|
103
118
|
|
|
104
119
|
def make_converter(datatype):
|
|
105
120
|
is_array = get_dtype(datatype) is not None
|
|
106
121
|
is_sequence = get_origin(datatype) == abc.Sequence
|
|
107
|
-
is_enum =
|
|
122
|
+
is_enum = inspect.isclass(datatype) and (
|
|
123
|
+
issubclass(datatype, Enum) or issubclass(datatype, RuntimeSubsetEnum)
|
|
124
|
+
)
|
|
108
125
|
|
|
109
126
|
if is_array or is_sequence:
|
|
110
127
|
return SoftArrayConverter()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Dict, Optional, Tuple, Type, TypedDict
|
|
4
|
+
|
|
5
|
+
from ophyd_async.core.signal_backend import RuntimeSubsetEnum
|
|
6
|
+
|
|
7
|
+
common_meta = {
|
|
8
|
+
"units",
|
|
9
|
+
"precision",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LimitPair(TypedDict):
|
|
14
|
+
high: float | None
|
|
15
|
+
low: float | None
|
|
16
|
+
|
|
17
|
+
def __bool__(self) -> bool:
|
|
18
|
+
return self.low is None and self.high is None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Limits(TypedDict):
|
|
22
|
+
alarm: LimitPair
|
|
23
|
+
control: LimitPair
|
|
24
|
+
display: LimitPair
|
|
25
|
+
warning: LimitPair
|
|
26
|
+
|
|
27
|
+
def __bool__(self) -> bool:
|
|
28
|
+
return any(self.alarm, self.control, self.display, self.warning)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_supported_values(
|
|
32
|
+
pv: str,
|
|
33
|
+
datatype: Optional[Type[str]],
|
|
34
|
+
pv_choices: Tuple[str, ...],
|
|
35
|
+
) -> Dict[str, str]:
|
|
36
|
+
if inspect.isclass(datatype) and issubclass(datatype, RuntimeSubsetEnum):
|
|
37
|
+
if not set(datatype.choices).issubset(set(pv_choices)):
|
|
38
|
+
raise TypeError(
|
|
39
|
+
f"{pv} has choices {pv_choices}, "
|
|
40
|
+
f"which is not a superset of {str(datatype)}."
|
|
41
|
+
)
|
|
42
|
+
return {x: x or "_" for x in pv_choices}
|
|
43
|
+
elif inspect.isclass(datatype) and issubclass(datatype, Enum):
|
|
44
|
+
if not issubclass(datatype, str):
|
|
45
|
+
raise TypeError(
|
|
46
|
+
f"{pv} is type Enum but {datatype} does not inherit from String."
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
choices = tuple(v.value for v in datatype)
|
|
50
|
+
if set(choices) != set(pv_choices):
|
|
51
|
+
raise TypeError(
|
|
52
|
+
f"{pv} has choices {pv_choices}, "
|
|
53
|
+
f"which do not match {datatype}, which has {choices}."
|
|
54
|
+
)
|
|
55
|
+
return {x: datatype(x) if x else "_" for x in pv_choices}
|
|
56
|
+
elif datatype is None:
|
|
57
|
+
return {x: x or "_" for x in pv_choices}
|
|
58
|
+
|
|
59
|
+
raise TypeError(
|
|
60
|
+
f"{pv} has choices {pv_choices}. "
|
|
61
|
+
"Use an Enum or SubsetEnum to represent this."
|
|
62
|
+
)
|
|
@@ -5,6 +5,7 @@ from ophyd_async.core import DEFAULT_TIMEOUT, wait_for_value
|
|
|
5
5
|
from ophyd_async.core.async_status import AsyncStatus
|
|
6
6
|
from ophyd_async.core.detector import DetectorControl, DetectorTrigger
|
|
7
7
|
from ophyd_async.epics.areadetector.drivers.ad_base import (
|
|
8
|
+
set_exposure_time_and_acquire_period_if_supplied,
|
|
8
9
|
start_acquiring_driver_and_ensure_status,
|
|
9
10
|
)
|
|
10
11
|
from ophyd_async.epics.areadetector.drivers.pilatus_driver import (
|
|
@@ -39,7 +40,9 @@ class PilatusController(DetectorControl):
|
|
|
39
40
|
exposure: Optional[float] = None,
|
|
40
41
|
) -> AsyncStatus:
|
|
41
42
|
if exposure is not None:
|
|
42
|
-
await
|
|
43
|
+
await set_exposure_time_and_acquire_period_if_supplied(
|
|
44
|
+
self, self._drv, exposure
|
|
45
|
+
)
|
|
43
46
|
await asyncio.gather(
|
|
44
47
|
self._drv.trigger_mode.set(self._get_trigger_mode(trigger)),
|
|
45
48
|
self._drv.num_images.set(999_999 if num == 0 else num),
|
{ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/__init__.py
RENAMED
|
@@ -2,6 +2,7 @@ from .ad_base import (
|
|
|
2
2
|
ADBase,
|
|
3
3
|
ADBaseShapeProvider,
|
|
4
4
|
DetectorState,
|
|
5
|
+
set_exposure_time_and_acquire_period_if_supplied,
|
|
5
6
|
start_acquiring_driver_and_ensure_status,
|
|
6
7
|
)
|
|
7
8
|
from .aravis_driver import AravisDriver
|
|
@@ -17,5 +18,6 @@ __all__ = [
|
|
|
17
18
|
"KinetixDriver",
|
|
18
19
|
"VimbaDriver",
|
|
19
20
|
"start_acquiring_driver_and_ensure_status",
|
|
21
|
+
"set_exposure_time_and_acquire_period_if_supplied",
|
|
20
22
|
"DetectorState",
|
|
21
23
|
]
|
{ophyd_async-0.3.2 → ophyd_async-0.3.4a1}/src/ophyd_async/epics/areadetector/drivers/ad_base.py
RENAMED
|
@@ -5,6 +5,7 @@ from typing import FrozenSet, Sequence, Set
|
|
|
5
5
|
from ophyd_async.core import (
|
|
6
6
|
DEFAULT_TIMEOUT,
|
|
7
7
|
AsyncStatus,
|
|
8
|
+
DetectorControl,
|
|
8
9
|
ShapeProvider,
|
|
9
10
|
set_and_wait_for_value,
|
|
10
11
|
)
|
|
@@ -44,6 +45,7 @@ class ADBase(NDArrayBase):
|
|
|
44
45
|
def __init__(self, prefix: str, name: str = "") -> None:
|
|
45
46
|
# Define some signals
|
|
46
47
|
self.acquire_time = epics_signal_rw_rbv(float, prefix + "AcquireTime")
|
|
48
|
+
self.acquire_period = epics_signal_rw_rbv(float, prefix + "AcquirePeriod")
|
|
47
49
|
self.num_images = epics_signal_rw_rbv(int, prefix + "NumImages")
|
|
48
50
|
self.image_mode = epics_signal_rw_rbv(ImageMode, prefix + "ImageMode")
|
|
49
51
|
self.detector_state = epics_signal_r(
|
|
@@ -52,6 +54,36 @@ class ADBase(NDArrayBase):
|
|
|
52
54
|
super().__init__(prefix, name=name)
|
|
53
55
|
|
|
54
56
|
|
|
57
|
+
async def set_exposure_time_and_acquire_period_if_supplied(
|
|
58
|
+
controller: DetectorControl,
|
|
59
|
+
driver: ADBase,
|
|
60
|
+
exposure: float | None = None,
|
|
61
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
62
|
+
) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Sets the exposure time if it is not None and the acquire period to the
|
|
65
|
+
exposure time plus the deadtime. This is expected behavior for most
|
|
66
|
+
AreaDetectors, but some may require more specialized handling.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
controller:
|
|
71
|
+
Controller that can supply a deadtime.
|
|
72
|
+
driver:
|
|
73
|
+
The driver to start acquiring. Must subclass ADBase.
|
|
74
|
+
exposure:
|
|
75
|
+
Desired exposure time, this is a noop if it is None.
|
|
76
|
+
timeout:
|
|
77
|
+
How long to wait for the exposure time and acquire period to be set.
|
|
78
|
+
"""
|
|
79
|
+
if exposure is not None:
|
|
80
|
+
full_frame_time = exposure + controller.get_deadtime(exposure)
|
|
81
|
+
await asyncio.gather(
|
|
82
|
+
driver.acquire_time.set(exposure, timeout=timeout),
|
|
83
|
+
driver.acquire_period.set(full_frame_time, timeout=timeout),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
55
87
|
async def start_acquiring_driver_and_ensure_status(
|
|
56
88
|
driver: ADBase,
|
|
57
89
|
good_states: Set[DetectorState] = set(DEFAULT_GOOD_STATES),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import Literal
|
|
3
2
|
|
|
3
|
+
from ophyd_async.core import SubsetEnum
|
|
4
4
|
from ophyd_async.epics.areadetector.drivers import ADBase
|
|
5
5
|
from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ class AravisTriggerMode(str, Enum):
|
|
|
19
19
|
To prevent requiring one Enum class per possible configuration, we set as this Enum
|
|
20
20
|
but read from the underlying signal as a str.
|
|
21
21
|
"""
|
|
22
|
-
AravisTriggerSource =
|
|
22
|
+
AravisTriggerSource = SubsetEnum["Freerun", "Line1"]
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class AravisDriver(ADBase):
|
|
@@ -34,5 +34,7 @@ class AravisDriver(ADBase):
|
|
|
34
34
|
self.trigger_mode = epics_signal_rw_rbv(
|
|
35
35
|
AravisTriggerMode, prefix + "TriggerMode"
|
|
36
36
|
)
|
|
37
|
-
self.trigger_source = epics_signal_rw_rbv(
|
|
37
|
+
self.trigger_source = epics_signal_rw_rbv(
|
|
38
|
+
AravisTriggerSource, prefix + "TriggerSource"
|
|
39
|
+
)
|
|
38
40
|
super().__init__(prefix, name=name)
|
|
@@ -95,5 +95,3 @@ class Motor(StandardReadable, Movable, Stoppable):
|
|
|
95
95
|
# Put with completion will never complete as we are waiting for completion on
|
|
96
96
|
# the move above, so need to pass wait=False
|
|
97
97
|
await self.motor_stop.trigger(wait=False)
|
|
98
|
-
# Trigger any callbacks
|
|
99
|
-
await self.user_readback._backend.put(await self.user_readback.get_value())
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4a1
|
|
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
|
|
@@ -156,6 +156,7 @@ tests/core/test_mock_signal_backend.py
|
|
|
156
156
|
tests/core/test_signal.py
|
|
157
157
|
tests/core/test_soft_signal_backend.py
|
|
158
158
|
tests/core/test_standard_readable.py
|
|
159
|
+
tests/core/test_subset_enum.py
|
|
159
160
|
tests/core/test_utils.py
|
|
160
161
|
tests/core/test_watchable_async_status.py
|
|
161
162
|
tests/epics/test_pvi.py
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from epicscorelibs.ca import dbr
|
|
3
|
+
from p4p import Value as P4PValue
|
|
4
|
+
from p4p.nt import NTEnum
|
|
5
|
+
|
|
6
|
+
from ophyd_async.core import SubsetEnum
|
|
7
|
+
from ophyd_async.epics._backend._aioca import make_converter as aioca_make_converter
|
|
8
|
+
from ophyd_async.epics._backend._p4p import make_converter as p4p_make_converter
|
|
9
|
+
from ophyd_async.epics.signal.signal import epics_signal_rw
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def test_runtime_enum_behaviour():
|
|
13
|
+
rt_enum = SubsetEnum["A", "B"]
|
|
14
|
+
|
|
15
|
+
with pytest.raises(RuntimeError) as exc:
|
|
16
|
+
rt_enum()
|
|
17
|
+
assert str(exc.value) == "SubsetEnum cannot be instantiated"
|
|
18
|
+
|
|
19
|
+
assert issubclass(rt_enum, SubsetEnum)
|
|
20
|
+
|
|
21
|
+
# Our metaclass doesn't cache already created runtime enums,
|
|
22
|
+
# so we can't do this
|
|
23
|
+
assert not issubclass(rt_enum, SubsetEnum["A", "B"])
|
|
24
|
+
assert not issubclass(rt_enum, SubsetEnum["B", "A"])
|
|
25
|
+
assert rt_enum is not SubsetEnum["A", "B"]
|
|
26
|
+
assert rt_enum is not SubsetEnum["B", "A"]
|
|
27
|
+
|
|
28
|
+
assert str(rt_enum) == "SubsetEnum['A', 'B']"
|
|
29
|
+
assert str(SubsetEnum) == "SubsetEnum"
|
|
30
|
+
|
|
31
|
+
with pytest.raises(TypeError) as exc:
|
|
32
|
+
SubsetEnum["A", "B", "A"]
|
|
33
|
+
assert str(exc.value) == "Duplicate elements in runtime enum choices."
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def test_ca_runtime_enum_converter():
|
|
37
|
+
class EpicsValue:
|
|
38
|
+
def __init__(self):
|
|
39
|
+
self.name = "test"
|
|
40
|
+
self.ok = (True,)
|
|
41
|
+
self.errorcode = 0
|
|
42
|
+
self.datatype = dbr.DBR_ENUM
|
|
43
|
+
self.element_count = 1
|
|
44
|
+
self.severity = 0
|
|
45
|
+
self.status = 0
|
|
46
|
+
self.raw_stamp = (0,)
|
|
47
|
+
self.timestamp = 0
|
|
48
|
+
self.datetime = 0
|
|
49
|
+
self.enums = ["A", "B", "C"] # More than the runtime enum
|
|
50
|
+
|
|
51
|
+
epics_value = EpicsValue()
|
|
52
|
+
rt_enum = SubsetEnum["A", "B"]
|
|
53
|
+
converter = aioca_make_converter(
|
|
54
|
+
rt_enum, values={"READ_PV": epics_value, "WRITE_PV": epics_value}
|
|
55
|
+
)
|
|
56
|
+
assert converter.choices == {"A": "A", "B": "B", "C": "C"}
|
|
57
|
+
assert set(rt_enum.choices).issubset(set(converter.choices.keys()))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def test_pva_runtime_enum_converter():
|
|
61
|
+
enum_type = NTEnum.buildType()
|
|
62
|
+
epics_value = P4PValue(
|
|
63
|
+
enum_type,
|
|
64
|
+
{
|
|
65
|
+
"value.choices": ["A", "B", "C"],
|
|
66
|
+
},
|
|
67
|
+
)
|
|
68
|
+
rt_enum = SubsetEnum["A", "B"]
|
|
69
|
+
converter = p4p_make_converter(
|
|
70
|
+
rt_enum, values={"READ_PV": epics_value, "WRITE_PV": epics_value}
|
|
71
|
+
)
|
|
72
|
+
assert {"A", "B"}.issubset(set(converter.choices))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def test_runtime_enum_signal():
|
|
76
|
+
signal_rw_pva = epics_signal_rw(SubsetEnum["A1", "B1"], "ca://RW_PV", name="signal")
|
|
77
|
+
signal_rw_ca = epics_signal_rw(SubsetEnum["A2", "B2"], "ca://RW_PV", name="signal")
|
|
78
|
+
await signal_rw_pva.connect(mock=True)
|
|
79
|
+
await signal_rw_ca.connect(mock=True)
|
|
80
|
+
await signal_rw_pva.get_value() == "A1"
|
|
81
|
+
await signal_rw_ca.get_value() == "A2"
|
|
82
|
+
await signal_rw_pva.set("B1")
|
|
83
|
+
await signal_rw_ca.set("B2")
|
|
84
|
+
await signal_rw_pva.get_value() == "B1"
|
|
85
|
+
await signal_rw_ca.get_value() == "B2"
|
|
86
|
+
|
|
87
|
+
# Will accept string values even if they're not in the runtime enum
|
|
88
|
+
# Though type checking should compain
|
|
89
|
+
await signal_rw_pva.set("C1") # type: ignore
|
|
90
|
+
await signal_rw_ca.set("C2") # type: ignore
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from unittest.mock import Mock
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from ophyd_async.core import (
|
|
7
|
+
DetectorControl,
|
|
8
|
+
DeviceCollector,
|
|
9
|
+
get_mock_put,
|
|
10
|
+
set_mock_value,
|
|
11
|
+
)
|
|
12
|
+
from ophyd_async.epics.areadetector.drivers import (
|
|
13
|
+
ADBase,
|
|
14
|
+
DetectorState,
|
|
15
|
+
set_exposure_time_and_acquire_period_if_supplied,
|
|
16
|
+
start_acquiring_driver_and_ensure_status,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
TEST_DEADTIME = 0.1
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def driver(RE) -> ADBase:
|
|
24
|
+
with DeviceCollector(mock=True):
|
|
25
|
+
driver = ADBase("DRV:", name="drv")
|
|
26
|
+
return driver
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture
|
|
30
|
+
async def controller(RE, driver: ADBase) -> Mock:
|
|
31
|
+
controller = Mock(spec=DetectorControl)
|
|
32
|
+
controller.get_deadtime.return_value = TEST_DEADTIME
|
|
33
|
+
return controller
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
async def test_set_exposure_time_and_acquire_period_if_supplied_is_a_noop_if_no_exposure_supplied( # noqa: E501
|
|
37
|
+
controller: DetectorControl,
|
|
38
|
+
driver: ADBase,
|
|
39
|
+
):
|
|
40
|
+
put_exposure = get_mock_put(driver.acquire_time)
|
|
41
|
+
put_acquire_period = get_mock_put(driver.acquire_period)
|
|
42
|
+
await set_exposure_time_and_acquire_period_if_supplied(controller, driver, None)
|
|
43
|
+
put_exposure.assert_not_called()
|
|
44
|
+
put_acquire_period.assert_not_called()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@pytest.mark.parametrize(
|
|
48
|
+
"exposure,expected_exposure,expected_acquire_period",
|
|
49
|
+
[
|
|
50
|
+
(0.0, 0.0, 0.1),
|
|
51
|
+
(1.0, 1.0, 1.1),
|
|
52
|
+
(1.5, 1.5, 1.6),
|
|
53
|
+
],
|
|
54
|
+
)
|
|
55
|
+
async def test_set_exposure_time_and_acquire_period_if_supplied_uses_deadtime(
|
|
56
|
+
controller: DetectorControl,
|
|
57
|
+
driver: ADBase,
|
|
58
|
+
exposure: float,
|
|
59
|
+
expected_exposure: float,
|
|
60
|
+
expected_acquire_period: float,
|
|
61
|
+
):
|
|
62
|
+
await set_exposure_time_and_acquire_period_if_supplied(controller, driver, exposure)
|
|
63
|
+
actual_exposure = await driver.acquire_time.get_value()
|
|
64
|
+
actual_acquire_period = await driver.acquire_period.get_value()
|
|
65
|
+
assert expected_exposure == actual_exposure
|
|
66
|
+
assert expected_acquire_period == actual_acquire_period
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
async def test_start_acquiring_driver_and_ensure_status_flags_immediate_failure(
|
|
70
|
+
driver: ADBase,
|
|
71
|
+
):
|
|
72
|
+
set_mock_value(driver.detector_state, DetectorState.Error)
|
|
73
|
+
acquiring = await start_acquiring_driver_and_ensure_status(driver, timeout=0.01)
|
|
74
|
+
with pytest.raises(ValueError):
|
|
75
|
+
await acquiring
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def test_start_acquiring_driver_and_ensure_status_fails_after_some_time(
|
|
79
|
+
driver: ADBase,
|
|
80
|
+
):
|
|
81
|
+
"""This test ensures a failing status is captured halfway through acquisition.
|
|
82
|
+
|
|
83
|
+
Real world application; it takes some time to start acquiring, and during that time
|
|
84
|
+
the detector gets itself into a bad state.
|
|
85
|
+
"""
|
|
86
|
+
set_mock_value(driver.detector_state, DetectorState.Idle)
|
|
87
|
+
|
|
88
|
+
async def wait_then_fail():
|
|
89
|
+
await asyncio.sleep(0)
|
|
90
|
+
set_mock_value(driver.detector_state, DetectorState.Disconnected)
|
|
91
|
+
|
|
92
|
+
acquiring = await start_acquiring_driver_and_ensure_status(driver, timeout=0.1)
|
|
93
|
+
await wait_then_fail()
|
|
94
|
+
|
|
95
|
+
with pytest.raises(ValueError):
|
|
96
|
+
await acquiring
|