ophyd-async 0.10.0a3__tar.gz → 0.10.1__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.10.0a3 → ophyd_async-0.10.1}/PKG-INFO +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/pyproject.toml +1 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/_version.py +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/__init__.py +4 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_derived_signal.py +39 -11
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_derived_signal_backend.py +7 -5
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_detector.py +4 -4
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_hdf_dataset.py +1 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_providers.py +1 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_signal.py +27 -6
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_signal_backend.py +19 -9
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_utils.py +31 -14
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_core_detector.py +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_core_io.py +3 -3
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_core_logic.py +34 -10
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_hdf_writer.py +15 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_utils.py +11 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adpilatus/_pilatus.py +1 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +4 -11
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_aioca.py +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_util.py +21 -13
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/eiger/_odin_io.py +12 -13
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/motor.py +3 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/eiger/_eiger.py +11 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +7 -3
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/eiger/_eiger_io.py +1 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_motor.py +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_base_device.py +2 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_converters.py +2 -6
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async.egg-info/PKG-INFO +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async.egg-info/requires.txt +1 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_multi_derived_signal.py +61 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_observe.py +56 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_signal.py +6 -0
- ophyd_async-0.10.1/tests/core/test_single_derived_signal.py +252 -0
- ophyd_async-0.10.1/tests/epics/adandor/test_andor.py +37 -0
- ophyd_async-0.10.1/tests/epics/adaravis/test_aravis.py +46 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_drivers.py +54 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_writers.py +16 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adpilatus/test_pilatus.py +38 -49
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/conftest.py +1 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/eiger/test_odin_io.py +22 -13
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/signal/test_common.py +39 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/test_motor.py +15 -3
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/eiger/test_eiger_controller.py +7 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/eiger/test_eiger_detector.py +20 -0
- ophyd_async-0.10.0a3/tests/core/test_single_derived_signal.py +0 -135
- ophyd_async-0.10.0a3/tests/epics/adandor/test_andor.py +0 -46
- ophyd_async-0.10.0a3/tests/epics/adaravis/test_aravis.py +0 -44
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.codecov.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.copier-answers.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/CONTRIBUTING.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/ISSUE_TEMPLATE/issue.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/actions/install_requirements/action.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/codeql/codeql-config.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/dependabot.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/pages/index.html +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_check.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_codeql.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_import_with_no_extras.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.gitignore +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/Dockerfile +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/LICENSE +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/README.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/_static/custom.css +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/conf.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0008-signal-types.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/0010-docstring-format.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/declarative-vs-procedural.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/design-goals.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/device-connection-strategies.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/devices-signals-backends.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/flyscanning.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations/where-device-logic.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/explanations.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/genindex.rst +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/choose-right-baseclass.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/derive-one-signal-from-others.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/implement-ad-detector.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/interact-with-signals.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/put-device-back.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to/store-and-retrieve.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/how-to.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/images/flyscan_collection_windows_and_frames.svg +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/images/ophyd-async-logo.svg +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/images/ophyd-favicon.svg +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/index.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/reference.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials/implementing-detectors.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials/implementing-devices.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials/using-devices.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials/writing-tests-for-devices.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/docs/tutorials.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/setup.cfg +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/_docs_parser.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_device.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_device_filler.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_flyer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_log.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_protocol.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_readable.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_settings.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_status.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_table.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/core/_yaml_settings.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adandor/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adandor/_andor.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/advimba/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_epics_device.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_p4p.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/core/_signal.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/__main__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/_ioc.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/_motor.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/_stage.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/motor.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/point_detector.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/eiger/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/signal.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/testing/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/testing/_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/testing/test_records.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/core.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_block.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_control.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_table.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_fly.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_panda.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_settings.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/py.typed +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/__main__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_blob_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_pattern_generator.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_point_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/sim/_stage.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_signal.py +8 -8
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_tango_transport.py +12 -12
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/core/_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/_counter.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/_mover.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/testing/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/tango/testing/_one_of_everything.py +2 -2
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_assert.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_one_of_everything.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_single_derived.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async.egg-info/SOURCES.txt +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/system_tests/epics/eiger/README.md +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/system_tests/epics/eiger/test_eiger_system.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/conftest.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_auto_init_devices.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_device.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_flyer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_log.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_mock_signal_backend.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_protocol.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_providers.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_readable.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_soft_signal_backend.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_status.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_subset_enum.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_table.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_cont_acq_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_detectors.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_scans.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adcore/test_single_trigger.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adkinetix/test_kinetix.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/adsimdetector/test_sim.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/advimba/test_vimba.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/demo/test_epics_demo.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/pvi/test_pvi.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/signal/test_signals.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/signal/test_yaml_save_ca.yaml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/signal/test_yaml_save_pva.yaml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/epics/test_areadetector_subclass_naming.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/db/panda.db +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_hdf_panda.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_panda_control.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_seq_table.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_trigger.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/fastcs/panda/test_writer.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/plan_stubs/test_ensure_connected.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/plan_stubs/test_settings.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/plan_stubs/test_setup.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/sim/__init__.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/sim/test_sim_blob_detector.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/sim/test_sim_motor.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/tango/conftest.py +1 -1
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/tango/context_subprocess.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/tango/test_base_device.py +10 -10
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/tango/test_tango_signals.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/tango/test_tango_transport.py +9 -9
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/test_cli.py +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/test_data/test_yaml_config_save.yaml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/test_data/test_yaml_save.yaml +0 -0
- {ophyd_async-0.10.0a3 → ophyd_async-0.10.1}/tests/test_tutorials.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.10.
|
|
3
|
+
Version: 0.10.1
|
|
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
|
|
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
|
|
|
43
43
|
License-File: LICENSE
|
|
44
44
|
Requires-Dist: numpy
|
|
45
45
|
Requires-Dist: bluesky>=1.13.1rc2
|
|
46
|
-
Requires-Dist: event-model>=1.
|
|
46
|
+
Requires-Dist: event-model>=1.23
|
|
47
47
|
Requires-Dist: pyyaml
|
|
48
48
|
Requires-Dist: colorlog
|
|
49
49
|
Requires-Dist: pydantic>=2.0
|
|
@@ -15,7 +15,7 @@ description = "Asynchronous Bluesky hardware abstraction code, compatible with c
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"numpy",
|
|
17
17
|
"bluesky>=1.13.1rc2",
|
|
18
|
-
"event-model>=1.
|
|
18
|
+
"event-model>=1.23",
|
|
19
19
|
"pyyaml",
|
|
20
20
|
"colorlog",
|
|
21
21
|
"pydantic>=2.0",
|
|
@@ -134,7 +134,6 @@ commands =
|
|
|
134
134
|
"""
|
|
135
135
|
|
|
136
136
|
[tool.ruff]
|
|
137
|
-
src = ["src", "tests", "system_tests"]
|
|
138
137
|
line-length = 88
|
|
139
138
|
lint.select = [
|
|
140
139
|
"B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b
|
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.10.
|
|
21
|
-
__version_tuple__ = version_tuple = (0, 10,
|
|
20
|
+
__version__ = version = '0.10.1'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 10, 1)
|
|
@@ -75,11 +75,13 @@ from ._utils import (
|
|
|
75
75
|
DEFAULT_TIMEOUT,
|
|
76
76
|
CalculatableTimeout,
|
|
77
77
|
Callback,
|
|
78
|
+
EnumTypes,
|
|
78
79
|
LazyMock,
|
|
79
80
|
NotConnected,
|
|
80
81
|
Reference,
|
|
81
82
|
StrictEnum,
|
|
82
83
|
SubsetEnum,
|
|
84
|
+
SupersetEnum,
|
|
83
85
|
WatcherUpdate,
|
|
84
86
|
gather_dict,
|
|
85
87
|
get_dtype,
|
|
@@ -122,6 +124,8 @@ __all__ = [
|
|
|
122
124
|
"Array1D",
|
|
123
125
|
"StrictEnum",
|
|
124
126
|
"SubsetEnum",
|
|
127
|
+
"SupersetEnum",
|
|
128
|
+
"EnumTypes",
|
|
125
129
|
"Table",
|
|
126
130
|
"SignalMetadata",
|
|
127
131
|
# Soft signal
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from collections.abc import Awaitable, Callable
|
|
2
|
-
from typing import Any, Generic, get_type_hints, is_typeddict
|
|
2
|
+
from typing import Any, Generic, get_args, get_origin, get_type_hints, is_typeddict
|
|
3
|
+
|
|
4
|
+
from bluesky.protocols import Locatable
|
|
3
5
|
|
|
4
6
|
from ._derived_signal_backend import (
|
|
5
7
|
DerivedSignalBackend,
|
|
@@ -8,7 +10,7 @@ from ._derived_signal_backend import (
|
|
|
8
10
|
TransformT,
|
|
9
11
|
)
|
|
10
12
|
from ._device import Device
|
|
11
|
-
from ._signal import SignalR, SignalRW, SignalT, SignalW
|
|
13
|
+
from ._signal import Signal, SignalR, SignalRW, SignalT, SignalW
|
|
12
14
|
from ._signal_backend import SignalDatatypeT
|
|
13
15
|
|
|
14
16
|
|
|
@@ -35,15 +37,27 @@ class DerivedSignalFactory(Generic[TransformT]):
|
|
|
35
37
|
self._set_derived = set_derived
|
|
36
38
|
# Check the raw and transform devices match the input arguments of the Transform
|
|
37
39
|
if transform_cls is not Transform:
|
|
38
|
-
expected
|
|
39
|
-
|
|
40
|
-
for
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
# Populate expected parameters and types
|
|
41
|
+
expected = {
|
|
42
|
+
**{k: f.annotation for k, f in transform_cls.model_fields.items()},
|
|
43
|
+
**{
|
|
44
|
+
k: v
|
|
45
|
+
for k, v in get_type_hints(transform_cls.raw_to_derived).items()
|
|
46
|
+
if k not in {"self", "return"}
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
# Populate received parameters and types
|
|
51
|
+
# Use Signal datatype, or Locatable datatype, or set type as None
|
|
52
|
+
received = {
|
|
53
|
+
k: v.datatype if isinstance(v, Signal) else get_locatable_type(v)
|
|
54
|
+
for k, v in raw_and_transform_devices.items()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if expected != received:
|
|
44
58
|
msg = (
|
|
45
|
-
f"Expected devices to be passed as keyword arguments
|
|
46
|
-
f"got {
|
|
59
|
+
f"Expected devices to be passed as keyword arguments "
|
|
60
|
+
f"{expected}, got {received}"
|
|
47
61
|
)
|
|
48
62
|
raise TypeError(msg)
|
|
49
63
|
self._set_derived_takes_dict = (
|
|
@@ -234,7 +248,7 @@ def derived_signal_rw(
|
|
|
234
248
|
if raw_to_derived_datatype != set_derived_datatype:
|
|
235
249
|
msg = (
|
|
236
250
|
f"{raw_to_derived} has datatype {raw_to_derived_datatype} "
|
|
237
|
-
f"!= {set_derived_datatype}
|
|
251
|
+
f"!= {set_derived_datatype} datatype {set_derived_datatype}"
|
|
238
252
|
)
|
|
239
253
|
raise TypeError(msg)
|
|
240
254
|
|
|
@@ -269,3 +283,17 @@ def derived_signal_w(
|
|
|
269
283
|
units=derived_units,
|
|
270
284
|
precision=derived_precision,
|
|
271
285
|
)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def get_locatable_type(obj: object) -> type | None:
|
|
289
|
+
"""Extract datatype from Locatable parent class.
|
|
290
|
+
|
|
291
|
+
:param obj: Object with possible Locatable inheritance
|
|
292
|
+
:return: Type hint associated with Locatable, or None if not found.
|
|
293
|
+
"""
|
|
294
|
+
for base in getattr(obj.__class__, "__orig_bases__", []):
|
|
295
|
+
if get_origin(base) is Locatable:
|
|
296
|
+
args = get_args(base)
|
|
297
|
+
if args:
|
|
298
|
+
return args[0]
|
|
299
|
+
return None
|
|
@@ -61,7 +61,7 @@ class Transform(BaseModel, Generic[RawT, DerivedT]):
|
|
|
61
61
|
TransformT = TypeVar("TransformT", bound=Transform)
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def
|
|
64
|
+
def validate_by_type(raw_devices: Mapping[str, Any], type_: type[T]) -> dict[str, T]:
|
|
65
65
|
filtered_devices: dict[str, T] = {}
|
|
66
66
|
for name, device in raw_devices.items():
|
|
67
67
|
if not isinstance(device, type_):
|
|
@@ -91,21 +91,23 @@ class SignalTransformer(Generic[TransformT]):
|
|
|
91
91
|
|
|
92
92
|
@cached_property
|
|
93
93
|
def raw_locatables(self) -> dict[str, AsyncLocatable]:
|
|
94
|
-
return
|
|
94
|
+
return validate_by_type(self._raw_devices, AsyncLocatable)
|
|
95
95
|
|
|
96
96
|
@cached_property
|
|
97
97
|
def transform_readables(self) -> dict[str, AsyncReadable]:
|
|
98
|
-
return
|
|
98
|
+
return validate_by_type(self._transform_devices, AsyncReadable)
|
|
99
99
|
|
|
100
100
|
@cached_property
|
|
101
101
|
def raw_and_transform_readables(self) -> dict[str, AsyncReadable]:
|
|
102
|
-
return
|
|
102
|
+
return validate_by_type(
|
|
103
103
|
self._raw_devices | self._transform_devices, AsyncReadable
|
|
104
104
|
)
|
|
105
105
|
|
|
106
106
|
@cached_property
|
|
107
107
|
def raw_and_transform_subscribables(self) -> dict[str, Subscribable]:
|
|
108
|
-
return
|
|
108
|
+
return validate_by_type(
|
|
109
|
+
self._raw_devices | self._transform_devices, Subscribable
|
|
110
|
+
)
|
|
109
111
|
|
|
110
112
|
def _complete_cached_reading(self) -> dict[str, Reading] | None:
|
|
111
113
|
if self._cached_readings and len(self._cached_readings) == len(
|
|
@@ -328,10 +328,10 @@ class StandardDetector(
|
|
|
328
328
|
if isinstance(value.number_of_events, list)
|
|
329
329
|
else [value.number_of_events]
|
|
330
330
|
)
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
331
|
+
|
|
332
|
+
await self._controller.prepare(value)
|
|
333
|
+
self._describe = await self._writer.open(self.name, value.exposures_per_event)
|
|
334
|
+
|
|
335
335
|
self._initial_frame = await self._writer.get_indices_written()
|
|
336
336
|
if value.trigger != DetectorTrigger.INTERNAL:
|
|
337
337
|
await self._controller.arm()
|
|
@@ -23,7 +23,7 @@ class HDFDatasetDescription(BaseModel):
|
|
|
23
23
|
"""The dataset name within the HDF file,
|
|
24
24
|
e.g. /entry/data/data or /entry/instrument/NDAttributes/sum"""
|
|
25
25
|
|
|
26
|
-
shape: tuple[int, ...] = Field(default_factory=tuple)
|
|
26
|
+
shape: tuple[int | None, ...] = Field(default_factory=tuple)
|
|
27
27
|
"""The shape of a single event's data in the HDF file,
|
|
28
28
|
e.g. (1, 768, 1024) for arrays or () for scalars"""
|
|
29
29
|
|
|
@@ -100,6 +100,11 @@ class Signal(Device, Generic[SignalDatatypeT]):
|
|
|
100
100
|
"""
|
|
101
101
|
return self._connector.backend.source(self.name, read=True)
|
|
102
102
|
|
|
103
|
+
@property
|
|
104
|
+
def datatype(self) -> type[SignalDatatypeT] | None:
|
|
105
|
+
"""Returns the datatype of the signal."""
|
|
106
|
+
return self._connector.backend.datatype
|
|
107
|
+
|
|
103
108
|
|
|
104
109
|
SignalT = TypeVar("SignalT", bound=Signal)
|
|
105
110
|
|
|
@@ -158,7 +163,12 @@ class _SignalCache(Generic[SignalDatatypeT]):
|
|
|
158
163
|
self._notify(function, want_value)
|
|
159
164
|
|
|
160
165
|
def unsubscribe(self, function: Callback) -> bool:
|
|
161
|
-
self._listeners.pop(function)
|
|
166
|
+
_listener = self._listeners.pop(function, None)
|
|
167
|
+
if not _listener:
|
|
168
|
+
self._signal.log.warning(
|
|
169
|
+
f"Unsubscribe failed: subscriber {function} was not found "
|
|
170
|
+
f" in listeners list: {list(self._listeners)}"
|
|
171
|
+
)
|
|
162
172
|
return self._staged or bool(self._listeners)
|
|
163
173
|
|
|
164
174
|
def set_staged(self, staged: bool) -> bool:
|
|
@@ -431,8 +441,8 @@ async def observe_signals_value(
|
|
|
431
441
|
Call subscribe_value on all the signals at the start, and clear_sub on
|
|
432
442
|
it at the end.
|
|
433
443
|
:param timeout:
|
|
434
|
-
If given, how long to wait for
|
|
435
|
-
update is not produced in this time then raise asyncio.TimeoutError.
|
|
444
|
+
If given, how long to wait for ANY updated value from shared queue in seconds.
|
|
445
|
+
If an update is not produced in this time then raise asyncio.TimeoutError.
|
|
436
446
|
:param done_status:
|
|
437
447
|
If this status is complete, stop observing and make the iterator return.
|
|
438
448
|
If it raises an exception then this exception will be raised by the
|
|
@@ -454,8 +464,10 @@ async def observe_signals_value(
|
|
|
454
464
|
q: asyncio.Queue[tuple[SignalR[SignalDatatypeT], SignalDatatypeT] | Status] = (
|
|
455
465
|
asyncio.Queue()
|
|
456
466
|
)
|
|
457
|
-
|
|
467
|
+
# dict to store signal subscription to remove it later
|
|
458
468
|
cbs: dict[SignalR, Callback] = {}
|
|
469
|
+
|
|
470
|
+
# subscribe signal to update queue and fill cbs dict
|
|
459
471
|
for signal in signals:
|
|
460
472
|
|
|
461
473
|
def queue_value(value: SignalDatatypeT, signal=signal):
|
|
@@ -468,6 +480,7 @@ async def observe_signals_value(
|
|
|
468
480
|
done_status.add_callback(q.put_nowait)
|
|
469
481
|
overall_deadline = time.monotonic() + done_timeout if done_timeout else None
|
|
470
482
|
try:
|
|
483
|
+
last_item = ()
|
|
471
484
|
while True:
|
|
472
485
|
if overall_deadline and time.monotonic() >= overall_deadline:
|
|
473
486
|
raise asyncio.TimeoutError(
|
|
@@ -476,14 +489,22 @@ async def observe_signals_value(
|
|
|
476
489
|
f"timeout {done_timeout}s"
|
|
477
490
|
)
|
|
478
491
|
iteration_timeout = _get_iteration_timeout(timeout, overall_deadline)
|
|
479
|
-
|
|
492
|
+
try:
|
|
493
|
+
item = await asyncio.wait_for(q.get(), iteration_timeout)
|
|
494
|
+
except asyncio.TimeoutError as exc:
|
|
495
|
+
raise asyncio.TimeoutError(
|
|
496
|
+
f"Timeout Error while waiting {iteration_timeout}s to update "
|
|
497
|
+
f"{[signal.source for signal in signals]}. "
|
|
498
|
+
f"Last observed signal and value were {last_item}"
|
|
499
|
+
) from exc
|
|
480
500
|
if done_status and item is done_status:
|
|
481
501
|
if exc := done_status.exception():
|
|
482
502
|
raise exc
|
|
483
503
|
else:
|
|
484
504
|
break
|
|
485
505
|
else:
|
|
486
|
-
|
|
506
|
+
last_item = cast(tuple[SignalR[SignalDatatypeT], SignalDatatypeT], item)
|
|
507
|
+
yield last_item
|
|
487
508
|
finally:
|
|
488
509
|
for signal, cb in cbs.items():
|
|
489
510
|
signal.clear_sub(cb)
|
|
@@ -6,8 +6,16 @@ import numpy as np
|
|
|
6
6
|
from bluesky.protocols import Reading
|
|
7
7
|
from event_model import DataKey, Dtype, Limits
|
|
8
8
|
|
|
9
|
+
from ophyd_async.core._utils import (
|
|
10
|
+
Callback,
|
|
11
|
+
EnumTypes,
|
|
12
|
+
StrictEnum,
|
|
13
|
+
SubsetEnum,
|
|
14
|
+
SupersetEnum,
|
|
15
|
+
get_enum_cls,
|
|
16
|
+
)
|
|
17
|
+
|
|
9
18
|
from ._table import Table
|
|
10
|
-
from ._utils import Callback, StrictEnum, get_enum_cls
|
|
11
19
|
|
|
12
20
|
DTypeScalar_co = TypeVar("DTypeScalar_co", covariant=True, bound=np.generic)
|
|
13
21
|
"""A numpy dtype like [](#numpy.float64)."""
|
|
@@ -24,7 +32,7 @@ E.g. `Array1D[np.float64]` is a 1D numpy array of 64-bit floats."""
|
|
|
24
32
|
Primitive = bool | int | float | str
|
|
25
33
|
SignalDatatype = (
|
|
26
34
|
Primitive
|
|
27
|
-
|
|
|
35
|
+
| EnumTypes
|
|
28
36
|
| Array1D[np.bool_]
|
|
29
37
|
| Array1D[np.int8]
|
|
30
38
|
| Array1D[np.uint8]
|
|
@@ -39,16 +47,18 @@ SignalDatatype = (
|
|
|
39
47
|
| np.ndarray
|
|
40
48
|
| Sequence[str]
|
|
41
49
|
| Sequence[StrictEnum]
|
|
50
|
+
| Sequence[SubsetEnum]
|
|
51
|
+
| Sequence[SupersetEnum]
|
|
42
52
|
| Table
|
|
43
53
|
)
|
|
44
54
|
"""The supported [](#Signal) datatypes:
|
|
45
55
|
|
|
46
56
|
- A python primitive [](#bool), [](#int), [](#float), [](#str)
|
|
47
|
-
-
|
|
57
|
+
- An [](#EnumTypes) subclass
|
|
48
58
|
- A fixed datatype [](#Array1D) of numpy bool, signed and unsigned integers or float
|
|
49
59
|
- A [](#numpy.ndarray) which can change dimensions and datatype at runtime
|
|
50
60
|
- A sequence of [](#str)
|
|
51
|
-
- A sequence of [](#
|
|
61
|
+
- A sequence of [](#EnumTypes) subclasses
|
|
52
62
|
- A [](#Table) subclass
|
|
53
63
|
"""
|
|
54
64
|
# TODO: These typevars will not be needed when we drop python 3.11
|
|
@@ -58,7 +68,7 @@ PrimitiveT = TypeVar("PrimitiveT", bound=Primitive)
|
|
|
58
68
|
SignalDatatypeT = TypeVar("SignalDatatypeT", bound=SignalDatatype)
|
|
59
69
|
"""A typevar for a [](#SignalDatatype)."""
|
|
60
70
|
SignalDatatypeV = TypeVar("SignalDatatypeV", bound=SignalDatatype)
|
|
61
|
-
EnumT = TypeVar("EnumT", bound=
|
|
71
|
+
EnumT = TypeVar("EnumT", bound=EnumTypes)
|
|
62
72
|
TableT = TypeVar("TableT", bound=Table)
|
|
63
73
|
|
|
64
74
|
|
|
@@ -136,7 +146,7 @@ def _datakey_dtype(datatype: type[SignalDatatype]) -> Dtype:
|
|
|
136
146
|
or issubclass(datatype, Table)
|
|
137
147
|
):
|
|
138
148
|
return "array"
|
|
139
|
-
elif issubclass(datatype,
|
|
149
|
+
elif issubclass(datatype, EnumTypes):
|
|
140
150
|
return "string"
|
|
141
151
|
elif issubclass(datatype, Primitive):
|
|
142
152
|
return _primitive_dtype[datatype]
|
|
@@ -153,7 +163,7 @@ def _datakey_dtype_numpy(
|
|
|
153
163
|
elif (
|
|
154
164
|
get_origin(datatype) is Sequence
|
|
155
165
|
or datatype is str
|
|
156
|
-
or issubclass(datatype,
|
|
166
|
+
or issubclass(datatype, EnumTypes)
|
|
157
167
|
):
|
|
158
168
|
# TODO: use np.dtypes.StringDType when we can use in structured arrays
|
|
159
169
|
# https://github.com/numpy/numpy/issues/25693
|
|
@@ -166,8 +176,8 @@ def _datakey_dtype_numpy(
|
|
|
166
176
|
raise TypeError(f"Can't make dtype_numpy for {datatype}")
|
|
167
177
|
|
|
168
178
|
|
|
169
|
-
def _datakey_shape(value: SignalDatatype) -> list[int]:
|
|
170
|
-
if type(value) in _primitive_dtype or isinstance(value,
|
|
179
|
+
def _datakey_shape(value: SignalDatatype) -> list[int | None]:
|
|
180
|
+
if type(value) in _primitive_dtype or isinstance(value, EnumTypes):
|
|
171
181
|
return []
|
|
172
182
|
elif isinstance(value, np.ndarray):
|
|
173
183
|
return list(value.shape)
|
|
@@ -5,7 +5,15 @@ import logging
|
|
|
5
5
|
from collections.abc import Awaitable, Callable, Iterable, Mapping, Sequence
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from enum import Enum, EnumMeta
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import (
|
|
9
|
+
Any,
|
|
10
|
+
Generic,
|
|
11
|
+
Literal,
|
|
12
|
+
ParamSpec,
|
|
13
|
+
TypeVar,
|
|
14
|
+
get_args,
|
|
15
|
+
get_origin,
|
|
16
|
+
)
|
|
9
17
|
from unittest.mock import Mock
|
|
10
18
|
|
|
11
19
|
import numpy as np
|
|
@@ -19,20 +27,16 @@ DEFAULT_TIMEOUT = 10.0
|
|
|
19
27
|
logger = logging.getLogger("ophyd_async")
|
|
20
28
|
|
|
21
29
|
|
|
22
|
-
class
|
|
23
|
-
def __new__(
|
|
24
|
-
ret = super().__new__(
|
|
30
|
+
class UppercaseNameEnumMeta(EnumMeta):
|
|
31
|
+
def __new__(cls, *args, **kwargs):
|
|
32
|
+
ret = super().__new__(cls, *args, **kwargs)
|
|
25
33
|
lowercase_names = [x.name for x in ret if not x.name.isupper()] # type: ignore
|
|
26
34
|
if lowercase_names:
|
|
27
35
|
raise TypeError(f"Names {lowercase_names} should be uppercase")
|
|
28
36
|
return ret
|
|
29
37
|
|
|
30
38
|
|
|
31
|
-
class
|
|
32
|
-
"""All members should exist in the Backend, and there will be no extras."""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class SubsetEnumMeta(StrictEnumMeta):
|
|
39
|
+
class AnyStringUppercaseNameEnumMeta(UppercaseNameEnumMeta):
|
|
36
40
|
def __call__(self, value, *args, **kwargs): # type: ignore
|
|
37
41
|
"""Return given value if it is a string and not a member of the enum.
|
|
38
42
|
|
|
@@ -54,10 +58,21 @@ class SubsetEnumMeta(StrictEnumMeta):
|
|
|
54
58
|
return super().__call__(value, *args, **kwargs)
|
|
55
59
|
|
|
56
60
|
|
|
57
|
-
class
|
|
61
|
+
class StrictEnum(str, Enum, metaclass=UppercaseNameEnumMeta):
|
|
62
|
+
"""All members should exist in the Backend, and there will be no extras."""
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class SubsetEnum(str, Enum, metaclass=AnyStringUppercaseNameEnumMeta):
|
|
58
66
|
"""All members should exist in the Backend, but there may be extras."""
|
|
59
67
|
|
|
60
68
|
|
|
69
|
+
class SupersetEnum(str, Enum, metaclass=UppercaseNameEnumMeta):
|
|
70
|
+
"""Some members should exist in the Backend, and there should be no extras."""
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
EnumTypes = StrictEnum | SubsetEnum | SupersetEnum
|
|
74
|
+
|
|
75
|
+
|
|
61
76
|
CALCULATE_TIMEOUT = "CALCULATE_TIMEOUT"
|
|
62
77
|
"""Sentinel used to implement ``myfunc(timeout=CalculateTimeout)``
|
|
63
78
|
|
|
@@ -207,10 +222,11 @@ def get_dtype(datatype: type) -> np.dtype:
|
|
|
207
222
|
return np.dtype(get_args(get_args(datatype)[1])[0])
|
|
208
223
|
|
|
209
224
|
|
|
210
|
-
def get_enum_cls(datatype: type | None) -> type[
|
|
225
|
+
def get_enum_cls(datatype: type | None) -> type[EnumTypes] | None:
|
|
211
226
|
"""Get the enum class from a datatype.
|
|
212
227
|
|
|
213
|
-
:raises TypeError: if type is not a [](#StrictEnum) or [](#SubsetEnum)
|
|
228
|
+
:raises TypeError: if type is not a [](#StrictEnum) or [](#SubsetEnum)
|
|
229
|
+
or [](#SupersetEnum) subclass
|
|
214
230
|
```python
|
|
215
231
|
>>> from ophyd_async.core import StrictEnum
|
|
216
232
|
>>> from collections.abc import Sequence
|
|
@@ -227,10 +243,11 @@ def get_enum_cls(datatype: type | None) -> type[StrictEnum] | None:
|
|
|
227
243
|
if get_origin(datatype) is Sequence:
|
|
228
244
|
datatype = get_args(datatype)[0]
|
|
229
245
|
if datatype and issubclass(datatype, Enum):
|
|
230
|
-
if not issubclass(datatype,
|
|
246
|
+
if not issubclass(datatype, EnumTypes):
|
|
231
247
|
raise TypeError(
|
|
232
248
|
f"{datatype} should inherit from ophyd_async.core.SubsetEnum "
|
|
233
|
-
"or ophyd_async.core.StrictEnum"
|
|
249
|
+
"or ophyd_async.core.StrictEnum "
|
|
250
|
+
"or ophyd_async.core.SupersetEnum."
|
|
234
251
|
)
|
|
235
252
|
return datatype
|
|
236
253
|
return None
|
|
@@ -22,8 +22,8 @@ class AreaDetector(StandardDetector[ADBaseControllerT, ADWriter]):
|
|
|
22
22
|
self.fileio = writer.fileio
|
|
23
23
|
|
|
24
24
|
if plugins is not None:
|
|
25
|
-
for
|
|
26
|
-
setattr(self,
|
|
25
|
+
for plugin_name, plugin in plugins.items():
|
|
26
|
+
setattr(self, plugin_name, plugin)
|
|
27
27
|
|
|
28
28
|
super().__init__(
|
|
29
29
|
controller,
|
|
@@ -70,14 +70,14 @@ class NDPluginStatsIO(NDPluginBaseIO):
|
|
|
70
70
|
# Basic statistics
|
|
71
71
|
compute_statistics: A[SignalRW[bool], PvSuffix.rbv("ComputeStatistics")]
|
|
72
72
|
bgd_width: A[SignalRW[int], PvSuffix.rbv("BgdWidth")]
|
|
73
|
-
|
|
73
|
+
total: A[SignalR[float], PvSuffix.rbv("Total")]
|
|
74
74
|
# Centroid statistics
|
|
75
75
|
compute_centroid: A[SignalRW[bool], PvSuffix.rbv("ComputeCentroid")]
|
|
76
76
|
centroid_threshold: A[SignalRW[float], PvSuffix.rbv("CentroidThreshold")]
|
|
77
77
|
# X and Y Profiles
|
|
78
78
|
compute_profiles: A[SignalRW[bool], PvSuffix.rbv("ComputeProfiles")]
|
|
79
|
-
profile_size_x: A[
|
|
80
|
-
profile_size_y: A[
|
|
79
|
+
profile_size_x: A[SignalR[int], PvSuffix.rbv("ProfileSizeX")]
|
|
80
|
+
profile_size_y: A[SignalR[int], PvSuffix.rbv("ProfileSizeY")]
|
|
81
81
|
cursor_x: A[SignalRW[int], PvSuffix.rbv("CursorX")]
|
|
82
82
|
cursor_y: A[SignalRW[int], PvSuffix.rbv("CursorY")]
|
|
83
83
|
# Array Histogram
|
|
@@ -7,6 +7,7 @@ from ophyd_async.core import (
|
|
|
7
7
|
DetectorController,
|
|
8
8
|
DetectorTrigger,
|
|
9
9
|
TriggerInfo,
|
|
10
|
+
observe_value,
|
|
10
11
|
set_and_wait_for_value,
|
|
11
12
|
)
|
|
12
13
|
|
|
@@ -89,34 +90,57 @@ class ADBaseController(DetectorController, Generic[ADBaseIOT]):
|
|
|
89
90
|
self.driver.acquire_period.set(full_frame_time, timeout=timeout),
|
|
90
91
|
)
|
|
91
92
|
|
|
92
|
-
async def start_acquiring_driver_and_ensure_status(
|
|
93
|
+
async def start_acquiring_driver_and_ensure_status(
|
|
94
|
+
self,
|
|
95
|
+
start_timeout: float = DEFAULT_TIMEOUT,
|
|
96
|
+
state_timeout: float = DEFAULT_TIMEOUT,
|
|
97
|
+
) -> AsyncStatus:
|
|
93
98
|
"""Start acquiring driver, raising ValueError if the detector is in a bad state.
|
|
94
99
|
|
|
95
100
|
This sets driver.acquire to True, and waits for it to be True up to a timeout.
|
|
96
101
|
Then, it checks that the DetectorState PV is in DEFAULT_GOOD_STATES,
|
|
97
102
|
and otherwise raises a ValueError.
|
|
98
103
|
|
|
104
|
+
|
|
105
|
+
:param start_timeout:
|
|
106
|
+
Timeout used for waiting for the driver to start
|
|
107
|
+
acquiring.
|
|
108
|
+
:param state_timeout:
|
|
109
|
+
Timeout used for waiting for the detector to be in a good
|
|
110
|
+
state after it stops acquiring.
|
|
99
111
|
:returns AsyncStatus:
|
|
100
112
|
An AsyncStatus that can be awaited to set driver.acquire to True and perform
|
|
101
113
|
subsequent raising (if applicable) due to detector state.
|
|
114
|
+
|
|
102
115
|
"""
|
|
103
116
|
status = await set_and_wait_for_value(
|
|
104
117
|
self.driver.acquire,
|
|
105
118
|
True,
|
|
106
|
-
timeout=
|
|
119
|
+
timeout=start_timeout,
|
|
107
120
|
wait_for_set_completion=False,
|
|
108
121
|
)
|
|
109
122
|
|
|
110
123
|
async def complete_acquisition() -> None:
|
|
111
|
-
# NOTE: possible race condition here between the callback from
|
|
112
|
-
# set_and_wait_for_value and the detector state updating.
|
|
113
124
|
await status
|
|
114
|
-
state =
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
state = None
|
|
126
|
+
try:
|
|
127
|
+
async for state in observe_value(
|
|
128
|
+
self.driver.detector_state, done_timeout=state_timeout
|
|
129
|
+
):
|
|
130
|
+
if state in self.good_states:
|
|
131
|
+
return
|
|
132
|
+
except asyncio.TimeoutError as exc:
|
|
133
|
+
if state is not None:
|
|
134
|
+
raise ValueError(
|
|
135
|
+
f"Final detector state {state.value} not in valid end "
|
|
136
|
+
f"states: {self.good_states}"
|
|
137
|
+
) from exc
|
|
138
|
+
else:
|
|
139
|
+
# No updates from the detector, something else is wrong
|
|
140
|
+
raise asyncio.TimeoutError(
|
|
141
|
+
"Could not monitor detector state: "
|
|
142
|
+
+ self.driver.detector_state.source
|
|
143
|
+
) from exc
|
|
120
144
|
|
|
121
145
|
return AsyncStatus(complete_acquisition())
|
|
122
146
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
from collections.abc import AsyncIterator
|
|
3
3
|
from pathlib import Path
|
|
4
|
+
from typing import TypeGuard
|
|
4
5
|
from xml.etree import ElementTree as ET
|
|
5
6
|
|
|
6
7
|
from bluesky.protocols import StreamAsset
|
|
@@ -22,6 +23,10 @@ from ._utils import (
|
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
|
|
26
|
+
def _is_fully_described(shape: tuple[int | None, ...]) -> TypeGuard[tuple[int, ...]]:
|
|
27
|
+
return None not in shape
|
|
28
|
+
|
|
29
|
+
|
|
25
30
|
class ADHDFWriter(ADWriter[NDFileHDFIO]):
|
|
26
31
|
"""Allow `NDFileHDFIO` to be used within `StandardDetector`."""
|
|
27
32
|
|
|
@@ -75,6 +80,16 @@ class ADHDFWriter(ADWriter[NDFileHDFIO]):
|
|
|
75
80
|
# Determine number of frames that will be saved per HDF chunk
|
|
76
81
|
frames_per_chunk = await self.fileio.num_frames_chunks.get_value()
|
|
77
82
|
|
|
83
|
+
if not _is_fully_described(detector_shape):
|
|
84
|
+
# Questions:
|
|
85
|
+
# - Can AreaDetector support this?
|
|
86
|
+
# - How to deal with chunking?
|
|
87
|
+
# Don't support for now - leave option open to support it later
|
|
88
|
+
raise ValueError(
|
|
89
|
+
"Datasets with partially unknown dimensionality "
|
|
90
|
+
"are not currently supported by ADHDFWriter."
|
|
91
|
+
)
|
|
92
|
+
|
|
78
93
|
# Add the main data
|
|
79
94
|
self._datasets = [
|
|
80
95
|
HDFDatasetDescription(
|
|
@@ -7,11 +7,12 @@ from ophyd_async.core import (
|
|
|
7
7
|
SignalRW,
|
|
8
8
|
StrictEnum,
|
|
9
9
|
SubsetEnum,
|
|
10
|
+
SupersetEnum,
|
|
10
11
|
wait_for_value,
|
|
11
12
|
)
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
class ADBaseDataType(
|
|
15
|
+
class ADBaseDataType(SupersetEnum):
|
|
15
16
|
INT8 = "Int8"
|
|
16
17
|
UINT8 = "UInt8"
|
|
17
18
|
INT16 = "Int16"
|
|
@@ -22,6 +23,9 @@ class ADBaseDataType(StrictEnum):
|
|
|
22
23
|
UINT64 = "UInt64"
|
|
23
24
|
FLOAT32 = "Float32"
|
|
24
25
|
FLOAT64 = "Float64"
|
|
26
|
+
# Driver database override will blank the enum string if it doesn't
|
|
27
|
+
# support a datatype
|
|
28
|
+
UNDEFINED = ""
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
def convert_ad_dtype_to_np(ad_dtype: ADBaseDataType) -> str:
|
|
@@ -37,7 +41,12 @@ def convert_ad_dtype_to_np(ad_dtype: ADBaseDataType) -> str:
|
|
|
37
41
|
ADBaseDataType.FLOAT32: "<f4",
|
|
38
42
|
ADBaseDataType.FLOAT64: "<f8",
|
|
39
43
|
}
|
|
40
|
-
|
|
44
|
+
np_type = ad_dtype_to_np_dtype.get(ad_dtype)
|
|
45
|
+
if np_type is None:
|
|
46
|
+
raise ValueError(
|
|
47
|
+
"Areadetector driver has a blank DataType, this is not supported"
|
|
48
|
+
)
|
|
49
|
+
return np_type
|
|
41
50
|
|
|
42
51
|
|
|
43
52
|
def convert_pv_dtype_to_np(datatype: str) -> str:
|
|
@@ -27,7 +27,7 @@ class PilatusDetector(AreaDetector[PilatusController]):
|
|
|
27
27
|
config_sigs: Sequence[SignalR] = (),
|
|
28
28
|
):
|
|
29
29
|
driver = PilatusDriverIO(prefix + drv_suffix)
|
|
30
|
-
controller = PilatusController(driver)
|
|
30
|
+
controller = PilatusController(driver, readout_time=readout_time)
|
|
31
31
|
|
|
32
32
|
writer = writer_cls.with_io(
|
|
33
33
|
prefix,
|