ophyd-async 0.3.1a1__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/PKG-INFO +2 -2
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/pyproject.toml +1 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/_version.py +2 -2
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/__init__.py +47 -44
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/device_save_loader.py +1 -23
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/signal.py +52 -19
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/signal_backend.py +47 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/soft_signal_backend.py +50 -19
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/_backend/_aioca.py +95 -18
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/_backend/_p4p.py +81 -16
- ophyd_async-0.3.3/src/ophyd_async/epics/_backend/common.py +62 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +4 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/__init__.py +2 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +32 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/motion/motor.py +0 -2
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/pvi/pvi.py +26 -6
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_common_blocks.py +2 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_hdf_panda.py +0 -2
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_table.py +10 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/writers/_hdf_writer.py +22 -105
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/writers/_panda_hdf_file.py +4 -8
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/PKG-INFO +2 -2
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/SOURCES.txt +3 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/requires.txt +1 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_device_save_loader.py +99 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_mock_signal_backend.py +32 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_signal.py +31 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_soft_signal_backend.py +38 -2
- ophyd_async-0.3.3/tests/core/test_subset_enum.py +90 -0
- ophyd_async-0.3.3/tests/epics/areadetector/test_drivers.py +96 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_pilatus.py +8 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/demo/test_demo.py +1 -1
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/test_pvi.py +58 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/test_records.db +28 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/test_signals.py +356 -88
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_hdf_panda.py +22 -24
- ophyd_async-0.3.3/tests/panda/test_writer.py +198 -0
- ophyd_async-0.3.3/tests/test_data/test_yaml_save.yml +22 -0
- ophyd_async-0.3.1a1/src/ophyd_async/epics/_backend/common.py +0 -25
- ophyd_async-0.3.1a1/tests/epics/areadetector/test_drivers.py +0 -47
- ophyd_async-0.3.1a1/tests/panda/test_writer.py +0 -208
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.codecov.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.copier-answers.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/CONTRIBUTING.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/actions/install_requirements/action.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/dependabot.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/pages/index.html +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_check.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.gitignore +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.mailmap +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/Dockerfile +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/LICENSE +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/README.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/_templates/README +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/_templates/custom-class-template.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/_templates/custom-module-template.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/conf.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/examples/epics_demo.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/examples/foo_detector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/design-goals.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/event-loop-choice.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations/flyscanning.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/explanations.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/genindex.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/choose-interfaces-for-devices.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/compound-devices.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/make-a-simple-device.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/make-a-standard-detector.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to/write-tests-for-devices.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/how-to.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/images/bluesky_ophyd_logo.svg +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/images/ophyd_favicon.svg +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/index.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/reference/api.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/reference.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/tutorials/using-existing-devices.rst +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/docs/tutorials.md +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/setup.cfg +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/async_status.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/detector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/device.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/flyer.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/mock_signal_backend.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/mock_signal_utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/standard_readable.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/core/utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/_backend/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/aravis.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/pilatus.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/demo/mover.db +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/demo/sensor.db +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/pvi/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/signal/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/epics/signal/signal.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/log.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_panda_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_trigger.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/_utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/panda/writers/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/plan_stubs/ensure_connected.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/plan_stubs/fly.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/protocols.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/demo/sim_motor.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/pattern_generator.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async/sim/sim_pattern_generator.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/entry_points.txt +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/conftest.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_async_status.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_device.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_device_collector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_flyer.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_standard_readable.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/_backend/test_common.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_aravis.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_controllers.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_kinetix.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_scans.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_single_trigger_det.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_vimba.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/areadetector/test_writers.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/demo/test_demo_ad_sim_detector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/motion/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/epics/motion/test_motor.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/db/panda.db +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_panda_controller.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_table.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/panda/test_trigger.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/protocols/test_protocols.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/conftest.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/demo/__init__.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/demo/test_sim_motor.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/test_pattern_generator.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/test_sim_detector.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/test_sim_writer.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/sim/test_streaming_plan.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/test_cli.py +0 -0
- {ophyd_async-0.3.1a1 → ophyd_async-0.3.3}/tests/test_log.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
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
|
|
@@ -41,7 +41,7 @@ Requires-Python: >=3.10
|
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
License-File: LICENSE
|
|
43
43
|
Requires-Dist: networkx>=2.0
|
|
44
|
-
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: numpy<2.0.0
|
|
45
45
|
Requires-Dist: packaging
|
|
46
46
|
Requires-Dist: pint
|
|
47
47
|
Requires-Dist: bluesky>=1.13.0a3
|
|
@@ -50,7 +50,7 @@ from .signal import (
|
|
|
50
50
|
soft_signal_rw,
|
|
51
51
|
wait_for_value,
|
|
52
52
|
)
|
|
53
|
-
from .signal_backend import SignalBackend
|
|
53
|
+
from .signal_backend import RuntimeSubsetEnum, SignalBackend, SubsetEnum
|
|
54
54
|
from .soft_signal_backend import SoftSignalBackend
|
|
55
55
|
from .standard_readable import ConfigSignal, HintedSignal, StandardReadable
|
|
56
56
|
from .utils import (
|
|
@@ -68,66 +68,69 @@ from .utils import (
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
__all__ = [
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"SoftSignalBackend",
|
|
71
|
+
"AsyncStatus",
|
|
72
|
+
"CalculatableTimeout",
|
|
73
|
+
"CalculateTimeout",
|
|
74
|
+
"Callback",
|
|
75
|
+
"ConfigSignal",
|
|
76
|
+
"DEFAULT_TIMEOUT",
|
|
78
77
|
"DetectorControl",
|
|
79
|
-
"MockSignalBackend",
|
|
80
78
|
"DetectorTrigger",
|
|
81
79
|
"DetectorWriter",
|
|
82
|
-
"StandardDetector",
|
|
83
80
|
"Device",
|
|
84
81
|
"DeviceCollector",
|
|
85
82
|
"DeviceVector",
|
|
86
|
-
"Signal",
|
|
87
|
-
"SignalR",
|
|
88
|
-
"SignalW",
|
|
89
|
-
"SignalRW",
|
|
90
|
-
"SignalX",
|
|
91
|
-
"soft_signal_r_and_setter",
|
|
92
|
-
"soft_signal_rw",
|
|
93
|
-
"observe_value",
|
|
94
|
-
"set_and_wait_for_value",
|
|
95
|
-
"set_mock_put_proceeds",
|
|
96
|
-
"set_mock_value",
|
|
97
|
-
"wait_for_value",
|
|
98
|
-
"AsyncStatus",
|
|
99
|
-
"WatchableAsyncStatus",
|
|
100
83
|
"DirectoryInfo",
|
|
101
84
|
"DirectoryProvider",
|
|
85
|
+
"HardwareTriggeredFlyable",
|
|
86
|
+
"HintedSignal",
|
|
87
|
+
"MockSignalBackend",
|
|
102
88
|
"NameProvider",
|
|
89
|
+
"NotConnected",
|
|
90
|
+
"ReadingValueCallback",
|
|
91
|
+
"RuntimeSubsetEnum",
|
|
92
|
+
"SubsetEnum",
|
|
103
93
|
"ShapeProvider",
|
|
104
|
-
"
|
|
94
|
+
"Signal",
|
|
95
|
+
"SignalBackend",
|
|
96
|
+
"SignalR",
|
|
97
|
+
"SignalRW",
|
|
98
|
+
"SignalW",
|
|
99
|
+
"SignalX",
|
|
100
|
+
"SoftSignalBackend",
|
|
101
|
+
"StandardDetector",
|
|
105
102
|
"StandardReadable",
|
|
106
|
-
"
|
|
107
|
-
"
|
|
103
|
+
"StaticDirectoryProvider",
|
|
104
|
+
"T",
|
|
108
105
|
"TriggerInfo",
|
|
109
106
|
"TriggerLogic",
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
"
|
|
116
|
-
"
|
|
117
|
-
"T",
|
|
107
|
+
"WatchableAsyncStatus",
|
|
108
|
+
"assert_configuration",
|
|
109
|
+
"assert_emitted",
|
|
110
|
+
"assert_mock_put_called_with",
|
|
111
|
+
"assert_reading",
|
|
112
|
+
"assert_value",
|
|
113
|
+
"callback_on_mock_put",
|
|
118
114
|
"get_dtype",
|
|
119
|
-
"
|
|
120
|
-
"merge_gathered_dicts",
|
|
121
|
-
"wait_for_connection",
|
|
115
|
+
"get_mock_put",
|
|
122
116
|
"get_signal_values",
|
|
117
|
+
"get_unique",
|
|
118
|
+
"load_device",
|
|
123
119
|
"load_from_yaml",
|
|
120
|
+
"merge_gathered_dicts",
|
|
121
|
+
"mock_puts_blocked",
|
|
122
|
+
"observe_value",
|
|
123
|
+
"reset_mock_put_calls",
|
|
124
|
+
"save_device",
|
|
124
125
|
"save_to_yaml",
|
|
126
|
+
"set_and_wait_for_value",
|
|
127
|
+
"set_mock_put_proceeds",
|
|
128
|
+
"set_mock_value",
|
|
129
|
+
"set_mock_values",
|
|
125
130
|
"set_signal_values",
|
|
131
|
+
"soft_signal_r_and_setter",
|
|
132
|
+
"soft_signal_rw",
|
|
133
|
+
"wait_for_connection",
|
|
134
|
+
"wait_for_value",
|
|
126
135
|
"walk_rw_signals",
|
|
127
|
-
"load_device",
|
|
128
|
-
"save_device",
|
|
129
|
-
"assert_reading",
|
|
130
|
-
"assert_value",
|
|
131
|
-
"assert_configuration",
|
|
132
|
-
"assert_emitted",
|
|
133
136
|
]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from
|
|
3
|
-
from typing import Any, Callable, Dict, Generator, List, Optional, Sequence, Union
|
|
2
|
+
from typing import Any, Callable, Dict, Generator, List, Optional, Sequence
|
|
4
3
|
|
|
5
4
|
import numpy as np
|
|
6
5
|
import numpy.typing as npt
|
|
@@ -8,13 +7,10 @@ import yaml
|
|
|
8
7
|
from bluesky.plan_stubs import abs_set, wait
|
|
9
8
|
from bluesky.protocols import Location
|
|
10
9
|
from bluesky.utils import Msg
|
|
11
|
-
from epicscorelibs.ca.dbr import ca_array, ca_float, ca_int, ca_str
|
|
12
10
|
|
|
13
11
|
from .device import Device
|
|
14
12
|
from .signal import SignalRW
|
|
15
13
|
|
|
16
|
-
CaType = Union[ca_float, ca_int, ca_str, ca_array]
|
|
17
|
-
|
|
18
14
|
|
|
19
15
|
def ndarray_representer(dumper: yaml.Dumper, array: npt.NDArray[Any]) -> yaml.Node:
|
|
20
16
|
return dumper.represent_sequence(
|
|
@@ -22,19 +18,6 @@ def ndarray_representer(dumper: yaml.Dumper, array: npt.NDArray[Any]) -> yaml.No
|
|
|
22
18
|
)
|
|
23
19
|
|
|
24
20
|
|
|
25
|
-
def ca_dbr_representer(dumper: yaml.Dumper, value: CaType) -> yaml.Node:
|
|
26
|
-
# if it's an array, just call ndarray_representer...
|
|
27
|
-
represent_array = partial(ndarray_representer, dumper)
|
|
28
|
-
|
|
29
|
-
representers: Dict[CaType, Callable[[CaType], yaml.Node]] = {
|
|
30
|
-
ca_float: dumper.represent_float,
|
|
31
|
-
ca_int: dumper.represent_int,
|
|
32
|
-
ca_str: dumper.represent_str,
|
|
33
|
-
ca_array: represent_array,
|
|
34
|
-
}
|
|
35
|
-
return representers[type(value)](value)
|
|
36
|
-
|
|
37
|
-
|
|
38
21
|
class OphydDumper(yaml.Dumper):
|
|
39
22
|
def represent_data(self, data: Any) -> Any:
|
|
40
23
|
if isinstance(data, Enum):
|
|
@@ -152,11 +135,6 @@ def save_to_yaml(phases: Sequence[Dict[str, Any]], save_path: str) -> None:
|
|
|
152
135
|
|
|
153
136
|
yaml.add_representer(np.ndarray, ndarray_representer, Dumper=yaml.Dumper)
|
|
154
137
|
|
|
155
|
-
yaml.add_representer(ca_float, ca_dbr_representer, Dumper=yaml.Dumper)
|
|
156
|
-
yaml.add_representer(ca_int, ca_dbr_representer, Dumper=yaml.Dumper)
|
|
157
|
-
yaml.add_representer(ca_str, ca_dbr_representer, Dumper=yaml.Dumper)
|
|
158
|
-
yaml.add_representer(ca_array, ca_dbr_representer, Dumper=yaml.Dumper)
|
|
159
|
-
|
|
160
138
|
with open(save_path, "w") as file:
|
|
161
139
|
yaml.dump(phases, file, Dumper=OphydDumper, default_flow_style=False)
|
|
162
140
|
|
|
@@ -31,7 +31,7 @@ from ophyd_async.protocols import AsyncConfigurable, AsyncReadable, AsyncStageab
|
|
|
31
31
|
from .async_status import AsyncStatus
|
|
32
32
|
from .device import Device
|
|
33
33
|
from .signal_backend import SignalBackend
|
|
34
|
-
from .soft_signal_backend import SoftSignalBackend
|
|
34
|
+
from .soft_signal_backend import SignalMetadata, SoftSignalBackend
|
|
35
35
|
from .utils import DEFAULT_TIMEOUT, CalculatableTimeout, CalculateTimeout, Callback, T
|
|
36
36
|
|
|
37
37
|
|
|
@@ -57,7 +57,7 @@ class Signal(Device, Generic[T]):
|
|
|
57
57
|
|
|
58
58
|
def __init__(
|
|
59
59
|
self,
|
|
60
|
-
backend: SignalBackend[T],
|
|
60
|
+
backend: Optional[SignalBackend[T]] = None,
|
|
61
61
|
timeout: Optional[float] = DEFAULT_TIMEOUT,
|
|
62
62
|
name: str = "",
|
|
63
63
|
) -> None:
|
|
@@ -66,13 +66,24 @@ class Signal(Device, Generic[T]):
|
|
|
66
66
|
super().__init__(name)
|
|
67
67
|
|
|
68
68
|
async def connect(
|
|
69
|
-
self,
|
|
69
|
+
self,
|
|
70
|
+
mock=False,
|
|
71
|
+
timeout=DEFAULT_TIMEOUT,
|
|
72
|
+
force_reconnect: bool = False,
|
|
73
|
+
backend: Optional[SignalBackend[T]] = None,
|
|
70
74
|
):
|
|
75
|
+
if backend:
|
|
76
|
+
if self._initial_backend and backend is not self._initial_backend:
|
|
77
|
+
raise ValueError(
|
|
78
|
+
"Backend at connection different from initialised one."
|
|
79
|
+
)
|
|
80
|
+
self._backend = backend
|
|
71
81
|
if mock and not isinstance(self._backend, MockSignalBackend):
|
|
72
82
|
# Using a soft backend, look to the initial value
|
|
73
|
-
self._backend = MockSignalBackend(
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
self._backend = MockSignalBackend(initial_backend=self._backend)
|
|
84
|
+
|
|
85
|
+
if self._backend is None:
|
|
86
|
+
raise RuntimeError("`connect` called on signal without backend")
|
|
76
87
|
self.log.debug(f"Connecting to {self.source}")
|
|
77
88
|
await self._backend.connect(timeout=timeout)
|
|
78
89
|
|
|
@@ -261,9 +272,17 @@ def soft_signal_rw(
|
|
|
261
272
|
datatype: Optional[Type[T]] = None,
|
|
262
273
|
initial_value: Optional[T] = None,
|
|
263
274
|
name: str = "",
|
|
275
|
+
units: str | None = None,
|
|
276
|
+
precision: int | None = None,
|
|
264
277
|
) -> SignalRW[T]:
|
|
265
|
-
"""Creates a read-writable Signal with a SoftSignalBackend
|
|
266
|
-
|
|
278
|
+
"""Creates a read-writable Signal with a SoftSignalBackend.
|
|
279
|
+
May pass metadata, which are propagated into describe.
|
|
280
|
+
"""
|
|
281
|
+
metadata = SignalMetadata(units=units, precision=precision)
|
|
282
|
+
signal = SignalRW(
|
|
283
|
+
SoftSignalBackend(datatype, initial_value, metadata=metadata),
|
|
284
|
+
name=name,
|
|
285
|
+
)
|
|
267
286
|
return signal
|
|
268
287
|
|
|
269
288
|
|
|
@@ -271,27 +290,31 @@ def soft_signal_r_and_setter(
|
|
|
271
290
|
datatype: Optional[Type[T]] = None,
|
|
272
291
|
initial_value: Optional[T] = None,
|
|
273
292
|
name: str = "",
|
|
293
|
+
units: str | None = None,
|
|
294
|
+
precision: int | None = None,
|
|
274
295
|
) -> Tuple[SignalR[T], Callable[[T], None]]:
|
|
275
296
|
"""Returns a tuple of a read-only Signal and a callable through
|
|
276
|
-
which the signal can be internally modified within the device.
|
|
277
|
-
|
|
297
|
+
which the signal can be internally modified within the device.
|
|
298
|
+
May pass metadata, which are propagated into describe.
|
|
299
|
+
Use soft_signal_rw if you want a device that is externally modifiable
|
|
278
300
|
"""
|
|
279
|
-
|
|
301
|
+
metadata = SignalMetadata(units=units, precision=precision)
|
|
302
|
+
backend = SoftSignalBackend(datatype, initial_value, metadata=metadata)
|
|
280
303
|
signal = SignalR(backend, name=name)
|
|
281
304
|
|
|
282
305
|
return (signal, backend.set_value)
|
|
283
306
|
|
|
284
307
|
|
|
285
308
|
def _generate_assert_error_msg(
|
|
286
|
-
name: str, expected_result: str,
|
|
309
|
+
name: str, expected_result: str, actual_result: str
|
|
287
310
|
) -> str:
|
|
288
311
|
WARNING = "\033[93m"
|
|
289
312
|
FAIL = "\033[91m"
|
|
290
313
|
ENDC = "\033[0m"
|
|
291
314
|
return (
|
|
292
315
|
f"Expected {WARNING}{name}{ENDC} to produce"
|
|
293
|
-
+ f"\n{FAIL}{
|
|
294
|
-
+ f"\nbut actually got \n{FAIL}{
|
|
316
|
+
+ f"\n{FAIL}{expected_result}{ENDC}"
|
|
317
|
+
+ f"\nbut actually got \n{FAIL}{actual_result}{ENDC}"
|
|
295
318
|
)
|
|
296
319
|
|
|
297
320
|
|
|
@@ -313,7 +336,9 @@ async def assert_value(signal: SignalR[T], value: Any) -> None:
|
|
|
313
336
|
"""
|
|
314
337
|
actual_value = await signal.get_value()
|
|
315
338
|
assert actual_value == value, _generate_assert_error_msg(
|
|
316
|
-
signal.name,
|
|
339
|
+
name=signal.name,
|
|
340
|
+
expected_result=value,
|
|
341
|
+
actual_result=actual_value,
|
|
317
342
|
)
|
|
318
343
|
|
|
319
344
|
|
|
@@ -338,7 +363,9 @@ async def assert_reading(
|
|
|
338
363
|
"""
|
|
339
364
|
actual_reading = await readable.read()
|
|
340
365
|
assert expected_reading == actual_reading, _generate_assert_error_msg(
|
|
341
|
-
readable.name,
|
|
366
|
+
name=readable.name,
|
|
367
|
+
expected_result=expected_reading,
|
|
368
|
+
actual_result=actual_reading,
|
|
342
369
|
)
|
|
343
370
|
|
|
344
371
|
|
|
@@ -364,7 +391,9 @@ async def assert_configuration(
|
|
|
364
391
|
"""
|
|
365
392
|
actual_configurable = await configurable.read_configuration()
|
|
366
393
|
assert configuration == actual_configurable, _generate_assert_error_msg(
|
|
367
|
-
configurable.name,
|
|
394
|
+
name=configurable.name,
|
|
395
|
+
expected_result=configuration,
|
|
396
|
+
actual_result=actual_configurable,
|
|
368
397
|
)
|
|
369
398
|
|
|
370
399
|
|
|
@@ -386,11 +415,15 @@ def assert_emitted(docs: Mapping[str, list[dict]], **numbers: int):
|
|
|
386
415
|
resource=1, datum=1, event=1, stop=1)
|
|
387
416
|
"""
|
|
388
417
|
assert list(docs) == list(numbers), _generate_assert_error_msg(
|
|
389
|
-
"documents",
|
|
418
|
+
name="documents",
|
|
419
|
+
expected_result=list(numbers),
|
|
420
|
+
actual_result=list(docs),
|
|
390
421
|
)
|
|
391
422
|
actual_numbers = {name: len(d) for name, d in docs.items()}
|
|
392
423
|
assert actual_numbers == numbers, _generate_assert_error_msg(
|
|
393
|
-
"emitted",
|
|
424
|
+
name="emitted",
|
|
425
|
+
expected_result=numbers,
|
|
426
|
+
actual_result=actual_numbers,
|
|
394
427
|
)
|
|
395
428
|
|
|
396
429
|
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import (
|
|
3
|
+
TYPE_CHECKING,
|
|
4
|
+
ClassVar,
|
|
5
|
+
Generic,
|
|
6
|
+
Literal,
|
|
7
|
+
Optional,
|
|
8
|
+
Tuple,
|
|
9
|
+
Type,
|
|
10
|
+
)
|
|
3
11
|
|
|
4
12
|
from bluesky.protocols import DataKey, Reading
|
|
5
13
|
|
|
@@ -45,3 +53,41 @@ class SignalBackend(Generic[T]):
|
|
|
45
53
|
@abstractmethod
|
|
46
54
|
def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
|
|
47
55
|
"""Observe changes to the current value, timestamp and severity"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class _RuntimeSubsetEnumMeta(type):
|
|
59
|
+
def __str__(cls):
|
|
60
|
+
if hasattr(cls, "choices"):
|
|
61
|
+
return f"SubsetEnum{list(cls.choices)}"
|
|
62
|
+
return "SubsetEnum"
|
|
63
|
+
|
|
64
|
+
def __getitem__(cls, _choices):
|
|
65
|
+
if isinstance(_choices, str):
|
|
66
|
+
_choices = (_choices,)
|
|
67
|
+
else:
|
|
68
|
+
if not isinstance(_choices, tuple) or not all(
|
|
69
|
+
isinstance(c, str) for c in _choices
|
|
70
|
+
):
|
|
71
|
+
raise TypeError(
|
|
72
|
+
"Choices must be a str or a tuple of str, " f"not {type(_choices)}."
|
|
73
|
+
)
|
|
74
|
+
if len(set(_choices)) != len(_choices):
|
|
75
|
+
raise TypeError("Duplicate elements in runtime enum choices.")
|
|
76
|
+
|
|
77
|
+
class _RuntimeSubsetEnum(cls):
|
|
78
|
+
choices = _choices
|
|
79
|
+
|
|
80
|
+
return _RuntimeSubsetEnum
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class RuntimeSubsetEnum(metaclass=_RuntimeSubsetEnumMeta):
|
|
84
|
+
choices: ClassVar[Tuple[str, ...]]
|
|
85
|
+
|
|
86
|
+
def __init__(self):
|
|
87
|
+
raise RuntimeError("SubsetEnum cannot be instantiated")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if TYPE_CHECKING:
|
|
91
|
+
SubsetEnum = Literal
|
|
92
|
+
else:
|
|
93
|
+
SubsetEnum = RuntimeSubsetEnum
|
|
@@ -3,14 +3,23 @@ from __future__ import annotations
|
|
|
3
3
|
import inspect
|
|
4
4
|
import time
|
|
5
5
|
from collections import abc
|
|
6
|
-
from dataclasses import dataclass
|
|
7
6
|
from enum import Enum
|
|
8
|
-
from typing import
|
|
7
|
+
from typing import (
|
|
8
|
+
Dict,
|
|
9
|
+
Generic,
|
|
10
|
+
Optional,
|
|
11
|
+
Tuple,
|
|
12
|
+
Type,
|
|
13
|
+
TypedDict,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
get_origin,
|
|
17
|
+
)
|
|
9
18
|
|
|
10
19
|
import numpy as np
|
|
11
20
|
from bluesky.protocols import DataKey, Dtype, Reading
|
|
12
21
|
|
|
13
|
-
from .signal_backend import SignalBackend
|
|
22
|
+
from .signal_backend import RuntimeSubsetEnum, SignalBackend
|
|
14
23
|
from .utils import DEFAULT_TIMEOUT, ReadingValueCallback, T, get_dtype
|
|
15
24
|
|
|
16
25
|
primitive_dtypes: Dict[type, Dtype] = {
|
|
@@ -21,6 +30,11 @@ primitive_dtypes: Dict[type, Dtype] = {
|
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
|
|
33
|
+
class SignalMetadata(TypedDict):
|
|
34
|
+
units: str | None = None
|
|
35
|
+
precision: int | None = None
|
|
36
|
+
|
|
37
|
+
|
|
24
38
|
class SoftConverter(Generic[T]):
|
|
25
39
|
def value(self, value: T) -> T:
|
|
26
40
|
return value
|
|
@@ -35,7 +49,8 @@ class SoftConverter(Generic[T]):
|
|
|
35
49
|
alarm_severity=-1 if severity > 2 else severity,
|
|
36
50
|
)
|
|
37
51
|
|
|
38
|
-
def get_datakey(self, source: str, value) -> DataKey:
|
|
52
|
+
def get_datakey(self, source: str, value, **metadata) -> DataKey:
|
|
53
|
+
dk = {"source": source, "shape": [], **metadata}
|
|
39
54
|
dtype = type(value)
|
|
40
55
|
if np.issubdtype(dtype, np.integer):
|
|
41
56
|
dtype = int
|
|
@@ -44,8 +59,8 @@ class SoftConverter(Generic[T]):
|
|
|
44
59
|
assert (
|
|
45
60
|
dtype in primitive_dtypes
|
|
46
61
|
), f"invalid converter for value of type {type(value)}"
|
|
47
|
-
|
|
48
|
-
return
|
|
62
|
+
dk["dtype"] = primitive_dtypes[dtype]
|
|
63
|
+
return dk
|
|
49
64
|
|
|
50
65
|
def make_initial_value(self, datatype: Optional[Type[T]]) -> T:
|
|
51
66
|
if datatype is None:
|
|
@@ -55,8 +70,8 @@ class SoftConverter(Generic[T]):
|
|
|
55
70
|
|
|
56
71
|
|
|
57
72
|
class SoftArrayConverter(SoftConverter):
|
|
58
|
-
def get_datakey(self, source: str, value) -> DataKey:
|
|
59
|
-
return {"source": source, "dtype": "array", "shape": [len(value)]}
|
|
73
|
+
def get_datakey(self, source: str, value, **metadata) -> DataKey:
|
|
74
|
+
return {"source": source, "dtype": "array", "shape": [len(value)], **metadata}
|
|
60
75
|
|
|
61
76
|
def make_initial_value(self, datatype: Optional[Type[T]]) -> T:
|
|
62
77
|
if datatype is None:
|
|
@@ -68,31 +83,45 @@ class SoftArrayConverter(SoftConverter):
|
|
|
68
83
|
return cast(T, datatype(shape=0)) # type: ignore
|
|
69
84
|
|
|
70
85
|
|
|
71
|
-
@dataclass
|
|
72
86
|
class SoftEnumConverter(SoftConverter):
|
|
73
|
-
|
|
87
|
+
choices: Tuple[str, ...]
|
|
74
88
|
|
|
75
|
-
def
|
|
89
|
+
def __init__(self, datatype: Union[RuntimeSubsetEnum, Enum]):
|
|
90
|
+
if issubclass(datatype, Enum):
|
|
91
|
+
self.choices = tuple(v.value for v in datatype)
|
|
92
|
+
else:
|
|
93
|
+
self.choices = datatype.choices
|
|
94
|
+
|
|
95
|
+
def write_value(self, value: Union[Enum, str]) -> str:
|
|
76
96
|
if isinstance(value, Enum):
|
|
97
|
+
return value.value
|
|
98
|
+
else: # Runtime enum
|
|
77
99
|
return value
|
|
78
|
-
else:
|
|
79
|
-
return self.enum_class(value)
|
|
80
100
|
|
|
81
|
-
def get_datakey(self, source: str, value) -> DataKey:
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
def get_datakey(self, source: str, value, **metadata) -> DataKey:
|
|
102
|
+
return {
|
|
103
|
+
"source": source,
|
|
104
|
+
"dtype": "string",
|
|
105
|
+
"shape": [],
|
|
106
|
+
"choices": self.choices,
|
|
107
|
+
**metadata,
|
|
108
|
+
}
|
|
84
109
|
|
|
85
110
|
def make_initial_value(self, datatype: Optional[Type[T]]) -> T:
|
|
86
111
|
if datatype is None:
|
|
87
112
|
return cast(T, None)
|
|
88
113
|
|
|
89
|
-
|
|
114
|
+
if issubclass(datatype, Enum):
|
|
115
|
+
return cast(T, list(datatype.__members__.values())[0]) # type: ignore
|
|
116
|
+
return cast(T, self.choices[0])
|
|
90
117
|
|
|
91
118
|
|
|
92
119
|
def make_converter(datatype):
|
|
93
120
|
is_array = get_dtype(datatype) is not None
|
|
94
121
|
is_sequence = get_origin(datatype) == abc.Sequence
|
|
95
|
-
is_enum =
|
|
122
|
+
is_enum = inspect.isclass(datatype) and (
|
|
123
|
+
issubclass(datatype, Enum) or issubclass(datatype, RuntimeSubsetEnum)
|
|
124
|
+
)
|
|
96
125
|
|
|
97
126
|
if is_array or is_sequence:
|
|
98
127
|
return SoftArrayConverter()
|
|
@@ -114,9 +143,11 @@ class SoftSignalBackend(SignalBackend[T]):
|
|
|
114
143
|
self,
|
|
115
144
|
datatype: Optional[Type[T]],
|
|
116
145
|
initial_value: Optional[T] = None,
|
|
146
|
+
metadata: SignalMetadata = None,
|
|
117
147
|
) -> None:
|
|
118
148
|
self.datatype = datatype
|
|
119
149
|
self._initial_value = initial_value
|
|
150
|
+
self._metadata = metadata or {}
|
|
120
151
|
self.converter: SoftConverter = make_converter(datatype)
|
|
121
152
|
if self._initial_value is None:
|
|
122
153
|
self._initial_value = self.converter.make_initial_value(self.datatype)
|
|
@@ -155,7 +186,7 @@ class SoftSignalBackend(SignalBackend[T]):
|
|
|
155
186
|
self.callback(reading, self._value)
|
|
156
187
|
|
|
157
188
|
async def get_datakey(self, source: str) -> DataKey:
|
|
158
|
-
return self.converter.get_datakey(source, self._value)
|
|
189
|
+
return self.converter.get_datakey(source, self._value, **self._metadata)
|
|
159
190
|
|
|
160
191
|
async def get_reading(self) -> Reading:
|
|
161
192
|
return self.converter.reading(self._value, self._timestamp, self._severity)
|