ophyd-async 0.8.0a4__tar.gz → 0.8.0a5__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.8.0a4 → ophyd_async-0.8.0a5}/PKG-INFO +1 -1
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/_version.py +1 -1
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_device.py +9 -2
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_signal.py +4 -7
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_soft_signal_backend.py +6 -2
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_utils.py +24 -19
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_aioca.py +1 -1
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_p4p.py +1 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_table.py +1 -1
- ophyd_async-0.8.0a5/src/ophyd_async/plan_stubs/_ensure_connected.py +33 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/PKG-INFO +1 -1
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/SOURCES.txt +1 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_device.py +5 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_device_save_loader.py +10 -15
- ophyd_async-0.8.0a5/tests/core/test_observe.py +90 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_signal.py +29 -13
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_soft_signal_backend.py +12 -15
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_utils.py +32 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_hdf_panda.py +1 -1
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_writer.py +4 -4
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/plan_stubs/test_ensure_connected.py +14 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/test_data/test_yaml_save.yml +0 -1
- ophyd_async-0.8.0a4/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -26
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.codecov.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.copier-answers.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/CONTRIBUTING.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/ISSUE_TEMPLATE/issue.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/actions/install_requirements/action.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/dependabot.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/pages/index.html +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_check.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.gitignore +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.mailmap +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/Dockerfile +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/LICENSE +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/README.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/_api.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/_templates/custom-module-template.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/conf.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/examples/epics_demo.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/examples/foo_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/examples/tango_demo.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0008-signal-types.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/design-goals.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/event-loop-choice.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations/flyscanning.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/explanations.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/genindex.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/choose-interfaces-for-devices.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/compound-devices.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/make-a-simple-device.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/make-a-standard-detector.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to/write-tests-for-devices.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/how-to.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/images/ophyd-async-logo.svg +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/images/ophyd-favicon.svg +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/index.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/reference.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/tutorials/using-existing-devices.rst +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/docs/tutorials.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/pyproject.toml +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/setup.cfg +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_device_filler.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_device_save_loader.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_flyer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_hdf_dataset.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_log.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_mock_signal_utils.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_protocol.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_readable.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_signal_backend.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_status.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/core/_table.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/_core_logic.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adcore/_utils.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/advimba/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_epics_device.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_signal.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/core/_util.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/demo/_mover.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/demo/_sensor.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/demo/mover.db +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/demo/sensor.db +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/eiger/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/eiger/_eiger.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/eiger/_eiger_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/eiger/_eiger_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/eiger/_odin_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/motor.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/epics/signal.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/core.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_block.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_control.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_utils.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/plan_stubs/_fly.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/py.typed +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_pattern_detector/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector_writer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_generator.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/demo/_sim_motor.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/sim/testing/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/base_devices/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/base_devices/_base_device.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/base_devices/_tango_readable.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/_counter.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/_mover.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/signal/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/signal/_signal.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async/tango/signal/_tango_transport.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/entry_points.txt +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/requires.txt +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/system_tests/epics/eiger/README.md +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/system_tests/epics/eiger/test_eiger_system.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/conftest.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_device_collector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_flyer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_log.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_mock_signal_backend.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_protocol.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_providers.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_readable.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_status.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_subset_enum.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_table.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adaravis/test_aravis.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adcore/test_drivers.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adcore/test_scans.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adcore/test_single_trigger.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adcore/test_writers.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adkinetix/test_kinetix.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adpilatus/test_pilatus.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/adsimdetector/test_sim.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/advimba/test_vimba.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/conftest.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/demo/test_demo.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/eiger/test_eiger_controller.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/eiger/test_eiger_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/eiger/test_odin_io.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/pvi/test_pvi.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/signal/test_common.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/signal/test_records.db +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/signal/test_signals.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/test_areadetector_subclass_naming.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/epics/test_motor.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/db/panda.db +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_panda_control.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_seq_table.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/fastcs/panda/test_trigger.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/conftest.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/demo/__init__.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/demo/test_sim_motor.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/test_pattern_generator.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/test_sim_detector.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/test_sim_writer.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/sim/test_streaming_plan.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/tango/test_base_device.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/tango/test_tango_signals.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/tango/test_tango_transport.py +0 -0
- {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a5}/tests/test_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.0a5
|
|
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
|
|
@@ -37,8 +37,14 @@ class DeviceConnector:
|
|
|
37
37
|
|
|
38
38
|
async def connect_mock(self, device: Device, mock: LazyMock):
|
|
39
39
|
# Connect serially, no errors to gather up as in mock mode
|
|
40
|
+
exceptions: dict[str, Exception] = {}
|
|
40
41
|
for name, child_device in device.children():
|
|
41
|
-
|
|
42
|
+
try:
|
|
43
|
+
await child_device.connect(mock=mock.child(name))
|
|
44
|
+
except Exception as e:
|
|
45
|
+
exceptions[name] = e
|
|
46
|
+
if exceptions:
|
|
47
|
+
raise NotConnected.with_other_exceptions_logged(exceptions)
|
|
42
48
|
|
|
43
49
|
async def connect_real(self, device: Device, timeout: float, force_reconnect: bool):
|
|
44
50
|
"""Used during ``Device.connect``.
|
|
@@ -193,7 +199,8 @@ class DeviceVector(MutableMapping[int, DeviceT], Device):
|
|
|
193
199
|
children: Mapping[int, DeviceT],
|
|
194
200
|
name: str = "",
|
|
195
201
|
) -> None:
|
|
196
|
-
self._children =
|
|
202
|
+
self._children: dict[int, DeviceT] = {}
|
|
203
|
+
self.update(children)
|
|
197
204
|
super().__init__(name=name)
|
|
198
205
|
|
|
199
206
|
def __setattr__(self, name: str, child: Any) -> None:
|
|
@@ -449,12 +449,6 @@ async def observe_value(
|
|
|
449
449
|
"""
|
|
450
450
|
|
|
451
451
|
q: asyncio.Queue[SignalDatatypeT | Status] = asyncio.Queue()
|
|
452
|
-
if timeout is None:
|
|
453
|
-
get_value = q.get
|
|
454
|
-
else:
|
|
455
|
-
|
|
456
|
-
async def get_value():
|
|
457
|
-
return await asyncio.wait_for(q.get(), timeout)
|
|
458
452
|
|
|
459
453
|
if done_status is not None:
|
|
460
454
|
done_status.add_callback(q.put_nowait)
|
|
@@ -462,7 +456,10 @@ async def observe_value(
|
|
|
462
456
|
signal.subscribe_value(q.put_nowait)
|
|
463
457
|
try:
|
|
464
458
|
while True:
|
|
465
|
-
|
|
459
|
+
# yield here in case something else is filling the queue
|
|
460
|
+
# like in test_observe_value_times_out_with_no_external_task()
|
|
461
|
+
await asyncio.sleep(0)
|
|
462
|
+
item = await asyncio.wait_for(q.get(), timeout)
|
|
466
463
|
if done_status and item is done_status:
|
|
467
464
|
if exc := done_status.exception():
|
|
468
465
|
raise exc
|
|
@@ -5,7 +5,7 @@ from abc import abstractmethod
|
|
|
5
5
|
from collections.abc import Sequence
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from functools import lru_cache
|
|
8
|
-
from typing import Any, Generic, get_origin
|
|
8
|
+
from typing import Any, Generic, get_args, get_origin
|
|
9
9
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
from bluesky.protocols import Reading
|
|
@@ -58,7 +58,7 @@ class SequenceEnumSoftConverter(SoftConverter[Sequence[EnumT]]):
|
|
|
58
58
|
|
|
59
59
|
@dataclass
|
|
60
60
|
class NDArraySoftConverter(SoftConverter[Array1D]):
|
|
61
|
-
datatype: np.dtype
|
|
61
|
+
datatype: np.dtype | None = None
|
|
62
62
|
|
|
63
63
|
def write_value(self, value: Any) -> Array1D:
|
|
64
64
|
return np.array(() if value is None else value, dtype=self.datatype)
|
|
@@ -98,7 +98,11 @@ def make_converter(datatype: type[SignalDatatype]) -> SoftConverter:
|
|
|
98
98
|
return SequenceStrSoftConverter()
|
|
99
99
|
elif get_origin(datatype) == Sequence and enum_cls:
|
|
100
100
|
return SequenceEnumSoftConverter(enum_cls)
|
|
101
|
+
elif datatype is np.ndarray:
|
|
102
|
+
return NDArraySoftConverter()
|
|
101
103
|
elif get_origin(datatype) == np.ndarray:
|
|
104
|
+
if datatype not in get_args(SignalDatatype):
|
|
105
|
+
raise TypeError(f"Expected Array1D[dtype], got {datatype}")
|
|
102
106
|
return NDArraySoftConverter(get_dtype(datatype))
|
|
103
107
|
elif enum_cls:
|
|
104
108
|
return EnumSoftConverter(enum_cls)
|
|
@@ -2,18 +2,10 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
-
from collections.abc import Awaitable, Callable, Iterable, Sequence
|
|
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
|
|
9
|
-
Any,
|
|
10
|
-
Generic,
|
|
11
|
-
Literal,
|
|
12
|
-
ParamSpec,
|
|
13
|
-
TypeVar,
|
|
14
|
-
get_args,
|
|
15
|
-
get_origin,
|
|
16
|
-
)
|
|
8
|
+
from typing import Any, Generic, Literal, ParamSpec, TypeVar, get_args, get_origin
|
|
17
9
|
from unittest.mock import Mock
|
|
18
10
|
|
|
19
11
|
import numpy as np
|
|
@@ -22,7 +14,7 @@ T = TypeVar("T")
|
|
|
22
14
|
P = ParamSpec("P")
|
|
23
15
|
Callback = Callable[[T], None]
|
|
24
16
|
DEFAULT_TIMEOUT = 10.0
|
|
25
|
-
ErrorText = str |
|
|
17
|
+
ErrorText = str | Mapping[str, Exception]
|
|
26
18
|
|
|
27
19
|
|
|
28
20
|
class StrictEnum(str, Enum):
|
|
@@ -70,6 +62,13 @@ class NotConnected(Exception):
|
|
|
70
62
|
|
|
71
63
|
self._errors = errors
|
|
72
64
|
|
|
65
|
+
@property
|
|
66
|
+
def sub_errors(self) -> Mapping[str, Exception]:
|
|
67
|
+
if isinstance(self._errors, dict):
|
|
68
|
+
return self._errors.copy()
|
|
69
|
+
else:
|
|
70
|
+
return {}
|
|
71
|
+
|
|
73
72
|
def _format_sub_errors(self, name: str, error: Exception, indent="") -> str:
|
|
74
73
|
if isinstance(error, NotConnected):
|
|
75
74
|
error_txt = ":" + error.format_error_string(indent + self._indent_width)
|
|
@@ -100,6 +99,19 @@ class NotConnected(Exception):
|
|
|
100
99
|
def __str__(self) -> str:
|
|
101
100
|
return self.format_error_string(indent="")
|
|
102
101
|
|
|
102
|
+
@classmethod
|
|
103
|
+
def with_other_exceptions_logged(
|
|
104
|
+
cls, exceptions: Mapping[str, Exception]
|
|
105
|
+
) -> NotConnected:
|
|
106
|
+
for name, exception in exceptions.items():
|
|
107
|
+
if not isinstance(exception, NotConnected):
|
|
108
|
+
logging.exception(
|
|
109
|
+
f"device `{name}` raised unexpected exception "
|
|
110
|
+
f"{type(exception).__name__}",
|
|
111
|
+
exc_info=exception,
|
|
112
|
+
)
|
|
113
|
+
return NotConnected(exceptions)
|
|
114
|
+
|
|
103
115
|
|
|
104
116
|
@dataclass(frozen=True)
|
|
105
117
|
class WatcherUpdate(Generic[T]):
|
|
@@ -137,14 +149,7 @@ async def wait_for_connection(**coros: Awaitable[None]):
|
|
|
137
149
|
exceptions[name] = result
|
|
138
150
|
|
|
139
151
|
if exceptions:
|
|
140
|
-
|
|
141
|
-
if not isinstance(exception, NotConnected):
|
|
142
|
-
logging.exception(
|
|
143
|
-
f"device `{name}` raised unexpected exception "
|
|
144
|
-
f"{type(exception).__name__}",
|
|
145
|
-
exc_info=exception,
|
|
146
|
-
)
|
|
147
|
-
raise NotConnected(exceptions)
|
|
152
|
+
raise NotConnected.with_other_exceptions_logged(exceptions)
|
|
148
153
|
|
|
149
154
|
|
|
150
155
|
def get_dtype(datatype: type) -> np.dtype:
|
|
@@ -115,7 +115,7 @@ class CaLongStrConverter(CaConverter[str]):
|
|
|
115
115
|
def __init__(self):
|
|
116
116
|
super().__init__(str, dbr.DBR_CHAR_STR, dbr.DBR_CHAR_STR)
|
|
117
117
|
|
|
118
|
-
def
|
|
118
|
+
def write_value(self, value: Any) -> Any:
|
|
119
119
|
# Add a null in here as this is what the commandline caput does
|
|
120
120
|
# TODO: this should be in the server so check if it can be pushed to asyn
|
|
121
121
|
return value + "\0"
|
|
@@ -188,6 +188,7 @@ _datatype_converter_from_typeid: dict[
|
|
|
188
188
|
("epics:nt/NTScalarArray:1.0", "as"): (Sequence[str], PvaConverter),
|
|
189
189
|
("epics:nt/NTTable:1.0", "S"): (Table, PvaTableConverter),
|
|
190
190
|
("epics:nt/NTNDArray:1.0", "v"): (np.ndarray, PvaNDArrayConverter),
|
|
191
|
+
("epics:nt/NTNDArray:1.0", "U"): (np.ndarray, PvaNDArrayConverter),
|
|
191
192
|
}
|
|
192
193
|
|
|
193
194
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from collections.abc import Awaitable
|
|
2
|
+
|
|
3
|
+
import bluesky.plan_stubs as bps
|
|
4
|
+
|
|
5
|
+
from ophyd_async.core import DEFAULT_TIMEOUT, Device, LazyMock, wait_for_connection
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def ensure_connected(
|
|
9
|
+
*devices: Device,
|
|
10
|
+
mock: bool | LazyMock = False,
|
|
11
|
+
timeout: float = DEFAULT_TIMEOUT,
|
|
12
|
+
force_reconnect=False,
|
|
13
|
+
):
|
|
14
|
+
device_names = [device.name for device in devices]
|
|
15
|
+
non_unique = {
|
|
16
|
+
device: device.name for device in devices if device_names.count(device.name) > 1
|
|
17
|
+
}
|
|
18
|
+
if non_unique:
|
|
19
|
+
raise ValueError(f"Devices do not have unique names {non_unique}")
|
|
20
|
+
|
|
21
|
+
def connect_devices() -> Awaitable[None]:
|
|
22
|
+
coros = {
|
|
23
|
+
device.name: device.connect(
|
|
24
|
+
mock=mock, timeout=timeout, force_reconnect=force_reconnect
|
|
25
|
+
)
|
|
26
|
+
for device in devices
|
|
27
|
+
}
|
|
28
|
+
return wait_for_connection(**coros)
|
|
29
|
+
|
|
30
|
+
(connect_task,) = yield from bps.wait_for([connect_devices])
|
|
31
|
+
|
|
32
|
+
if connect_task and connect_task.exception() is not None:
|
|
33
|
+
raise connect_task.exception()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.0a5
|
|
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
|
|
@@ -185,6 +185,7 @@ tests/core/test_device_save_loader.py
|
|
|
185
185
|
tests/core/test_flyer.py
|
|
186
186
|
tests/core/test_log.py
|
|
187
187
|
tests/core/test_mock_signal_backend.py
|
|
188
|
+
tests/core/test_observe.py
|
|
188
189
|
tests/core/test_protocol.py
|
|
189
190
|
tests/core/test_providers.py
|
|
190
191
|
tests/core/test_readable.py
|
|
@@ -117,10 +117,15 @@ async def test_device_with_device_collector():
|
|
|
117
117
|
parent = DummyDeviceGroup("parent")
|
|
118
118
|
|
|
119
119
|
assert parent.name == "parent"
|
|
120
|
+
assert parent.parent is None
|
|
120
121
|
assert parent.child1.name == "parent-child1"
|
|
122
|
+
assert parent.child1.parent == parent
|
|
121
123
|
assert parent._child2.name == "parent-child2"
|
|
124
|
+
assert parent._child2.parent == parent
|
|
122
125
|
assert parent.dict_with_children.name == "parent-dict_with_children"
|
|
126
|
+
assert parent.dict_with_children.parent == parent
|
|
123
127
|
assert parent.dict_with_children[123].name == "parent-dict_with_children-123"
|
|
128
|
+
assert parent.dict_with_children[123].parent == parent.dict_with_children
|
|
124
129
|
assert parent.child1.connected
|
|
125
130
|
assert parent.dict_with_children[123].connected
|
|
126
131
|
|
|
@@ -4,7 +4,6 @@ from typing import Any
|
|
|
4
4
|
from unittest.mock import patch
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
|
-
import numpy.typing as npt
|
|
8
7
|
import pytest
|
|
9
8
|
import yaml
|
|
10
9
|
from bluesky.run_engine import RunEngine
|
|
@@ -71,17 +70,16 @@ class DummyDeviceGroupAllTypes(Device):
|
|
|
71
70
|
self.pv_str: SignalRW = epics_signal_rw(str, "PV2")
|
|
72
71
|
self.pv_enum_str: SignalRW = epics_signal_rw(MyEnum, "PV3")
|
|
73
72
|
self.pv_enum: SignalRW = epics_signal_rw(MyEnum, "PV4")
|
|
74
|
-
self.pv_array_int8 = epics_signal_rw(
|
|
75
|
-
self.pv_array_uint8 = epics_signal_rw(
|
|
76
|
-
self.pv_array_int16 = epics_signal_rw(
|
|
77
|
-
self.pv_array_uint16 = epics_signal_rw(
|
|
78
|
-
self.pv_array_int32 = epics_signal_rw(
|
|
79
|
-
self.pv_array_uint32 = epics_signal_rw(
|
|
80
|
-
self.pv_array_int64 = epics_signal_rw(
|
|
81
|
-
self.pv_array_uint64 = epics_signal_rw(
|
|
82
|
-
self.pv_array_float32 = epics_signal_rw(
|
|
83
|
-
self.pv_array_float64 = epics_signal_rw(
|
|
84
|
-
self.pv_array_npstr = epics_signal_rw(npt.NDArray[np.str_], "PV15")
|
|
73
|
+
self.pv_array_int8 = epics_signal_rw(Array1D[np.int8], "PV5")
|
|
74
|
+
self.pv_array_uint8 = epics_signal_rw(Array1D[np.uint8], "PV6")
|
|
75
|
+
self.pv_array_int16 = epics_signal_rw(Array1D[np.int16], "PV7")
|
|
76
|
+
self.pv_array_uint16 = epics_signal_rw(Array1D[np.uint16], "PV8")
|
|
77
|
+
self.pv_array_int32 = epics_signal_rw(Array1D[np.int32], "PV9")
|
|
78
|
+
self.pv_array_uint32 = epics_signal_rw(Array1D[np.uint32], "PV10")
|
|
79
|
+
self.pv_array_int64 = epics_signal_rw(Array1D[np.int64], "PV11")
|
|
80
|
+
self.pv_array_uint64 = epics_signal_rw(Array1D[np.uint64], "PV12")
|
|
81
|
+
self.pv_array_float32 = epics_signal_rw(Array1D[np.float32], "PV13")
|
|
82
|
+
self.pv_array_float64 = epics_signal_rw(Array1D[np.float64], "PV14")
|
|
85
83
|
self.pv_array_str = epics_signal_rw(Sequence[str], "PV16")
|
|
86
84
|
self.pv_protocol_device_abstraction = epics_signal_rw(Table, "pva://PV17")
|
|
87
85
|
super().__init__(name)
|
|
@@ -168,9 +166,6 @@ async def test_save_device_all_types(
|
|
|
168
166
|
)
|
|
169
167
|
|
|
170
168
|
await pv.set(data)
|
|
171
|
-
await device_all_types.pv_array_npstr.set(
|
|
172
|
-
np.array(["one", "two", "three"], dtype=np.str_),
|
|
173
|
-
)
|
|
174
169
|
await device_all_types.pv_array_str.set(
|
|
175
170
|
["one", "two", "three"],
|
|
176
171
|
)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from ophyd_async.core import AsyncStatus, observe_value, soft_signal_r_and_setter
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def test_observe_value_working_correctly():
|
|
10
|
+
sig, setter = soft_signal_r_and_setter(float)
|
|
11
|
+
|
|
12
|
+
async def tick():
|
|
13
|
+
for i in range(2):
|
|
14
|
+
await asyncio.sleep(0.01)
|
|
15
|
+
setter(i + 1)
|
|
16
|
+
|
|
17
|
+
recv = []
|
|
18
|
+
status = AsyncStatus(tick())
|
|
19
|
+
async for val in observe_value(sig, done_status=status):
|
|
20
|
+
recv.append(val)
|
|
21
|
+
assert recv == [0, 1, 2]
|
|
22
|
+
await status
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async def test_observe_value_times_out():
|
|
26
|
+
sig, setter = soft_signal_r_and_setter(float)
|
|
27
|
+
|
|
28
|
+
async def tick():
|
|
29
|
+
for i in range(5):
|
|
30
|
+
await asyncio.sleep(0.1)
|
|
31
|
+
setter(i + 1)
|
|
32
|
+
|
|
33
|
+
recv = []
|
|
34
|
+
|
|
35
|
+
async def watch():
|
|
36
|
+
async for val in observe_value(sig):
|
|
37
|
+
recv.append(val)
|
|
38
|
+
|
|
39
|
+
t = asyncio.create_task(tick())
|
|
40
|
+
start = time.time()
|
|
41
|
+
try:
|
|
42
|
+
with pytest.raises(asyncio.TimeoutError):
|
|
43
|
+
await asyncio.wait_for(watch(), timeout=0.2)
|
|
44
|
+
assert recv == [0, 1]
|
|
45
|
+
assert time.time() - start == pytest.approx(0.2, abs=0.05)
|
|
46
|
+
finally:
|
|
47
|
+
t.cancel()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def test_observe_value_times_out_with_busy_sleep():
|
|
51
|
+
sig, setter = soft_signal_r_and_setter(float)
|
|
52
|
+
|
|
53
|
+
async def tick():
|
|
54
|
+
for i in range(5):
|
|
55
|
+
await asyncio.sleep(0.1)
|
|
56
|
+
setter(i + 1)
|
|
57
|
+
|
|
58
|
+
recv = []
|
|
59
|
+
|
|
60
|
+
async def watch():
|
|
61
|
+
async for val in observe_value(sig):
|
|
62
|
+
time.sleep(0.15)
|
|
63
|
+
recv.append(val)
|
|
64
|
+
|
|
65
|
+
t = asyncio.create_task(tick())
|
|
66
|
+
start = time.time()
|
|
67
|
+
try:
|
|
68
|
+
with pytest.raises(asyncio.TimeoutError):
|
|
69
|
+
await asyncio.wait_for(watch(), timeout=0.2)
|
|
70
|
+
assert recv == [0, 1]
|
|
71
|
+
assert time.time() - start == pytest.approx(0.3, abs=0.05)
|
|
72
|
+
finally:
|
|
73
|
+
t.cancel()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
async def test_observe_value_times_out_with_no_external_task():
|
|
77
|
+
sig, setter = soft_signal_r_and_setter(float)
|
|
78
|
+
|
|
79
|
+
recv = []
|
|
80
|
+
|
|
81
|
+
async def watch():
|
|
82
|
+
async for val in observe_value(sig):
|
|
83
|
+
recv.append(val)
|
|
84
|
+
setter(val + 1)
|
|
85
|
+
|
|
86
|
+
start = time.time()
|
|
87
|
+
with pytest.raises(asyncio.TimeoutError):
|
|
88
|
+
await asyncio.wait_for(watch(), timeout=0.1)
|
|
89
|
+
assert recv
|
|
90
|
+
assert time.time() - start == pytest.approx(0.1, abs=0.05)
|
|
@@ -5,6 +5,8 @@ import time
|
|
|
5
5
|
from asyncio import Event
|
|
6
6
|
from unittest.mock import ANY, Mock
|
|
7
7
|
|
|
8
|
+
import numpy as np
|
|
9
|
+
import numpy.typing as npt
|
|
8
10
|
import pytest
|
|
9
11
|
from bluesky.protocols import Reading
|
|
10
12
|
|
|
@@ -299,21 +301,35 @@ async def test_subscription_logs(caplog):
|
|
|
299
301
|
assert "Closing subscription on source" in caplog.text
|
|
300
302
|
|
|
301
303
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
self.some_attribute = "some_attribute"
|
|
304
|
+
class SomeClass:
|
|
305
|
+
def __init__(self):
|
|
306
|
+
self.some_attribute = "some_attribute"
|
|
306
307
|
|
|
307
|
-
|
|
308
|
-
|
|
308
|
+
def some_function(self):
|
|
309
|
+
pass
|
|
309
310
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
311
|
+
|
|
312
|
+
@pytest.mark.parametrize(
|
|
313
|
+
"datatype,err",
|
|
314
|
+
[
|
|
315
|
+
(SomeClass, "Can't make converter for %s"),
|
|
316
|
+
(object, "Can't make converter for %s"),
|
|
317
|
+
(dict, "Can't make converter for %s"),
|
|
318
|
+
(npt.NDArray[np.float64], "Expected Array1D[dtype], got %s"),
|
|
319
|
+
],
|
|
320
|
+
)
|
|
321
|
+
async def test_signal_unknown_datatype(datatype, err):
|
|
322
|
+
err_str = re.escape(err % datatype)
|
|
314
323
|
with pytest.raises(TypeError, match=err_str):
|
|
315
|
-
await epics_signal_rw(
|
|
324
|
+
await epics_signal_rw(datatype, "pva://mock_signal").connect(mock=True)
|
|
316
325
|
with pytest.raises(TypeError, match=err_str):
|
|
317
|
-
await epics_signal_rw(
|
|
326
|
+
await epics_signal_rw(datatype, "ca://mock_signal").connect(mock=True)
|
|
318
327
|
with pytest.raises(TypeError, match=err_str):
|
|
319
|
-
soft_signal_rw(
|
|
328
|
+
soft_signal_rw(datatype)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
async def test_soft_signal_ndarray_can_change_dtype():
|
|
332
|
+
sig = soft_signal_rw(np.ndarray)
|
|
333
|
+
for dtype in (np.int32, np.float64):
|
|
334
|
+
await sig.set(np.arange(4, dtype=dtype))
|
|
335
|
+
assert (await sig.get_value()).dtype == dtype
|
|
@@ -5,11 +5,11 @@ from collections.abc import Callable, Sequence
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
|
-
import numpy.typing as npt
|
|
9
8
|
import pytest
|
|
10
9
|
from bluesky.protocols import Reading
|
|
11
10
|
|
|
12
11
|
from ophyd_async.core import (
|
|
12
|
+
Array1D,
|
|
13
13
|
SignalBackend,
|
|
14
14
|
SoftSignalBackend,
|
|
15
15
|
StrictEnum,
|
|
@@ -81,20 +81,17 @@ default_int_type = (
|
|
|
81
81
|
(float, 0.0, 43.5, number_d, "<f8"),
|
|
82
82
|
(str, "", "goodbye", string_d, "|S40"),
|
|
83
83
|
(MyEnum, MyEnum.a, MyEnum.c, enum_d, "|S40"),
|
|
84
|
-
(
|
|
85
|
-
(
|
|
86
|
-
(
|
|
87
|
-
(
|
|
88
|
-
(
|
|
89
|
-
(
|
|
90
|
-
(
|
|
91
|
-
(
|
|
92
|
-
(
|
|
93
|
-
(
|
|
84
|
+
(Array1D[np.int8], [], [-8, 3, 44], waveform_d, "|i1"),
|
|
85
|
+
(Array1D[np.uint8], [], [218], waveform_d, "|u1"),
|
|
86
|
+
(Array1D[np.int16], [], [-855], waveform_d, "<i2"),
|
|
87
|
+
(Array1D[np.uint16], [], [5666], waveform_d, "<u2"),
|
|
88
|
+
(Array1D[np.int32], [], [-2], waveform_d, "<i4"),
|
|
89
|
+
(Array1D[np.uint32], [], [1022233], waveform_d, "<u4"),
|
|
90
|
+
(Array1D[np.int64], [], [-3], waveform_d, "<i8"),
|
|
91
|
+
(Array1D[np.uint64], [], [995444], waveform_d, "<u8"),
|
|
92
|
+
(Array1D[np.float32], [], [1.0], waveform_d, "<f4"),
|
|
93
|
+
(Array1D[np.float64], [], [0.2], waveform_d, "<f8"),
|
|
94
94
|
(Sequence[str], [], ["nine", "ten"], waveform_d, "|S40"),
|
|
95
|
-
# Can't do long strings until https://github.com/epics-base/pva2pva/issues/17
|
|
96
|
-
# (str, "longstr", ls1, ls2, string_d),
|
|
97
|
-
# (str, "longstr2.VAL$", ls1, ls2, string_d),
|
|
98
95
|
],
|
|
99
96
|
)
|
|
100
97
|
async def test_soft_signal_backend_get_put_monitor(
|
|
@@ -135,7 +132,7 @@ async def test_soft_signal_backend_enum_value_equivalence():
|
|
|
135
132
|
|
|
136
133
|
|
|
137
134
|
async def test_soft_signal_backend_with_numpy_typing():
|
|
138
|
-
soft_backend = SoftSignalBackend(
|
|
135
|
+
soft_backend = SoftSignalBackend(Array1D[np.float64])
|
|
139
136
|
await soft_backend.connect(timeout=1)
|
|
140
137
|
array = await soft_backend.get_value()
|
|
141
138
|
assert array.shape == (0,)
|
|
@@ -173,6 +173,38 @@ async def test_error_handling_value_errors(caplog):
|
|
|
173
173
|
assert f"signal {protocol}://A_NON_EXISTENT_SIGNAL timed out" in messages
|
|
174
174
|
|
|
175
175
|
|
|
176
|
+
class BadDatatypeDevice(Device):
|
|
177
|
+
def __init__(self, name: str = "") -> None:
|
|
178
|
+
self.sig = epics_signal_rw(object, "", "")
|
|
179
|
+
super().__init__(name)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
async def test_error_handling_device_collector_mock():
|
|
183
|
+
with pytest.raises(NotConnected) as e:
|
|
184
|
+
async with DeviceCollector(mock=True):
|
|
185
|
+
device = BadDatatypeDevice()
|
|
186
|
+
device2 = BadDatatypeDevice()
|
|
187
|
+
expected_output = NotConnected(
|
|
188
|
+
{
|
|
189
|
+
"device": NotConnected(
|
|
190
|
+
{"sig": TypeError(f"Can't make converter for {object}")}
|
|
191
|
+
),
|
|
192
|
+
"device2": NotConnected(
|
|
193
|
+
{"sig": TypeError(f"Can't make converter for {object}")}
|
|
194
|
+
),
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
assert str(expected_output) == str(e.value)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def test_introspecting_sub_errors():
|
|
201
|
+
sub_error1 = NotConnected("bad")
|
|
202
|
+
assert sub_error1.sub_errors == {}
|
|
203
|
+
sub_error2 = ValueError("very bad")
|
|
204
|
+
error = NotConnected({"child1": sub_error1, "child2": sub_error2})
|
|
205
|
+
assert error.sub_errors == {"child1": sub_error1, "child2": sub_error2}
|
|
206
|
+
|
|
207
|
+
|
|
176
208
|
async def test_error_handling_device_collector(caplog):
|
|
177
209
|
caplog.set_level(10)
|
|
178
210
|
with pytest.raises(NotConnected) as e:
|
|
@@ -47,7 +47,7 @@ async def mock_hdf_panda(tmp_path):
|
|
|
47
47
|
mock_hdf_panda.data.datasets,
|
|
48
48
|
DatasetTable(
|
|
49
49
|
name=["x", "y"],
|
|
50
|
-
|
|
50
|
+
dtype=[PandaHdf5DatasetType.UINT_32, PandaHdf5DatasetType.FLOAT_64],
|
|
51
51
|
),
|
|
52
52
|
)
|
|
53
53
|
|
|
@@ -27,11 +27,11 @@ from ophyd_async.fastcs.panda import (
|
|
|
27
27
|
TABLES = [
|
|
28
28
|
DatasetTable(
|
|
29
29
|
name=[],
|
|
30
|
-
|
|
30
|
+
dtype=[],
|
|
31
31
|
),
|
|
32
32
|
DatasetTable(
|
|
33
33
|
name=["x"],
|
|
34
|
-
|
|
34
|
+
dtype=[PandaHdf5DatasetType.UINT_32],
|
|
35
35
|
),
|
|
36
36
|
DatasetTable(
|
|
37
37
|
name=[
|
|
@@ -40,7 +40,7 @@ TABLES = [
|
|
|
40
40
|
"y_min",
|
|
41
41
|
"y_max",
|
|
42
42
|
],
|
|
43
|
-
|
|
43
|
+
dtype=[
|
|
44
44
|
PandaHdf5DatasetType.UINT_32,
|
|
45
45
|
PandaHdf5DatasetType.FLOAT_64,
|
|
46
46
|
PandaHdf5DatasetType.FLOAT_64,
|
|
@@ -82,7 +82,7 @@ async def mock_panda(panda_t):
|
|
|
82
82
|
mock_panda.data.datasets,
|
|
83
83
|
DatasetTable(
|
|
84
84
|
name=[],
|
|
85
|
-
|
|
85
|
+
dtype=[],
|
|
86
86
|
),
|
|
87
87
|
)
|
|
88
88
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
|
|
3
5
|
from ophyd_async.core import Device, NotConnected, soft_signal_rw
|
|
@@ -36,3 +38,15 @@ def test_ensure_connected(RE):
|
|
|
36
38
|
assert device2.signal._mock is not None
|
|
37
39
|
|
|
38
40
|
RE(connect_with_mocking())
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def test_ensure_connected_fails_for_non_unique_device_names(RE):
|
|
44
|
+
d1 = Device("dupe")
|
|
45
|
+
d2 = Device("dupe")
|
|
46
|
+
d3 = Device("ok")
|
|
47
|
+
non_unique = {d1: "dupe", d2: "dupe"}
|
|
48
|
+
with pytest.raises(
|
|
49
|
+
ValueError,
|
|
50
|
+
match=re.escape(f"Devices do not have unique names {non_unique}"),
|
|
51
|
+
):
|
|
52
|
+
RE(ensure_connected(d1, d2, d3))
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import bluesky.plan_stubs as bps
|
|
2
|
-
|
|
3
|
-
from ophyd_async.core import DEFAULT_TIMEOUT, Device, LazyMock, wait_for_connection
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def ensure_connected(
|
|
7
|
-
*devices: Device,
|
|
8
|
-
mock: bool | LazyMock = False,
|
|
9
|
-
timeout: float = DEFAULT_TIMEOUT,
|
|
10
|
-
force_reconnect=False,
|
|
11
|
-
):
|
|
12
|
-
(connect_task,) = yield from bps.wait_for(
|
|
13
|
-
[
|
|
14
|
-
lambda: wait_for_connection(
|
|
15
|
-
**{
|
|
16
|
-
device.name: device.connect(
|
|
17
|
-
mock=mock, timeout=timeout, force_reconnect=force_reconnect
|
|
18
|
-
)
|
|
19
|
-
for device in devices
|
|
20
|
-
}
|
|
21
|
-
)
|
|
22
|
-
]
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
if connect_task and connect_task.exception() is not None:
|
|
26
|
-
raise connect_task.exception()
|
|
File without changes
|