ophyd-async 0.14.1__tar.gz → 0.15__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.14.1 → ophyd_async-0.15}/.copier-answers.yml +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/CONTRIBUTING.md +1 -1
- {ophyd_async-0.14.1/src/ophyd_async.egg-info → ophyd_async-0.15}/PKG-INFO +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/conf.py +3 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/interact-with-signals.md +34 -9
- {ophyd_async-0.14.1 → ophyd_async-0.15}/pyproject.toml +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/_version.py +3 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/__init__.py +17 -5
- ophyd_async-0.14.1/src/ophyd_async/core/_table.py → ophyd_async-0.15/src/ophyd_async/core/_datatypes.py +18 -9
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_derived_signal.py +57 -24
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_derived_signal_backend.py +1 -5
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_device_filler.py +30 -7
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_mock_signal_backend.py +25 -7
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_mock_signal_utils.py +7 -11
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_signal.py +11 -11
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_signal_backend.py +7 -19
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_soft_signal_backend.py +6 -6
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_status.py +81 -4
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_utils.py +57 -7
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_core_io.py +12 -5
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_core_logic.py +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/__init__.py +2 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_aioca.py +13 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_epics_connector.py +4 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_p4p.py +13 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_signal.py +18 -6
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_util.py +23 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/_motor.py +2 -2
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/motor.py +15 -17
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/odin/_odin_io.py +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/pmac/_pmac_io.py +23 -4
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/pmac/_pmac_trajectory.py +47 -10
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/eiger/_eiger_io.py +20 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/jungfrau/_signals.py +4 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_block.py +28 -6
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_writer.py +1 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/_tango_transport.py +7 -17
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/_counter.py +2 -2
- {ophyd_async-0.14.1 → ophyd_async-0.15/src/ophyd_async.egg-info}/PKG-INFO +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async.egg-info/SOURCES.txt +2 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/conftest.py +9 -4
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/signal/test_signals.py +4 -4
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests_tango/test_tango_signals.py +4 -4
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests_tango/test_tango_transport.py +5 -10
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_device.py +54 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_mock_signal_backend.py +25 -30
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_multi_derived_signal.py +74 -12
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_observe.py +10 -6
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_single_derived_signal.py +33 -10
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_soft_signal_backend.py +3 -3
- ophyd_async-0.15/tests/unit_tests/core/test_status.py +452 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_utils.py +144 -2
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_writers.py +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/demo/test_epics_demo.py +9 -9
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/eiger/test_odin_io.py +8 -10
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pmac/test_pmac_trajectory.py +54 -9
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pvi/test_pvi.py +17 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/test_motor.py +35 -3
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/eiger/test_eiger_controller.py +6 -8
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/eiger/test_eiger_detector.py +1 -1
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/plan_stubs/test_settings.py +5 -5
- ophyd_async-0.15/tests/unit_tests/sim/__init__.py +0 -0
- ophyd_async-0.14.1/tests/unit_tests/core/test_status.py +0 -214
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.codecov.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.devcontainer/devcontainer.json +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.git-blame-ignore-revs +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/ISSUE_TEMPLATE/issue.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/codeql/codeql-config.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/pages/index.html +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/pages/make_switcher.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_codeql.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_dist.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_docs.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_pypi.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_release.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_test.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/_tox.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/ci.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/claude.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.github/workflows/periodic.yml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.gitignore +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.gitleaks.toml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.gitmodules +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.pre-commit-config.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/.python-version +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/Dockerfile +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/LICENSE +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/README.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/_static/custom.css +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0008-signal-types.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0010-docstring-format.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/0011-buffer-updates-camonitor.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions/COPYME +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/decisions.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/declarative-vs-procedural.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/design-goals.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/device-connection-strategies.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/devices-signals-backends.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/fly-scanning.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/plan-stubs.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/when-to-extend-movable.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations/where-device-logic.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/explanations.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/genindex.rst +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/choose-right-baseclass.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/contribute.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/derive-one-signal-from-others.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/implement-ad-detector.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/put-device-back.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to/store-and-retrieve.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/how-to.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/images/ophyd-async-logo.svg +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/images/ophyd-favicon.svg +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/index.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/reference.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials/implementing-detectors.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials/implementing-devices.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials/installation.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials/using-devices.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials/writing-tests-for-devices.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/docs/tutorials.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/renovate.json +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/setup.cfg +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/__main__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/_docs_parser.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_device.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_enums.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_flyer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_hdf_dataset.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_log.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_protocol.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_providers.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_readable.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_settings.py +0 -0
- /ophyd_async-0.14.1/src/ophyd_async/plan_stubs/_fly.py → /ophyd_async-0.15/src/ophyd_async/core/_typing.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/core/_yaml_settings.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adandor/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adandor/_andor.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adcore/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/advimba/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_epics_device.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/__main__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/_ioc.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/_stage.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/motor.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/point_detector.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/odin/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/pmac/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/pmac/_pmac_trajectory_generation.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/pmac/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/signal.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/testing/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/testing/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/testing/test_records.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/core.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/eiger/_eiger.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/jungfrau/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/jungfrau/_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/jungfrau/_jungfrau.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/jungfrau/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_control.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_table.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
- /ophyd_async-0.14.1/src/ophyd_async/py.typed → /ophyd_async-0.15/src/ophyd_async/plan_stubs/_fly.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_panda.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_settings.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
- /ophyd_async-0.14.1/tests/system_tests/__init__.py → /ophyd_async-0.15/src/ophyd_async/py.typed +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/__main__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_blob_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_motor.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_pattern_generator.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_point_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/sim/_stage.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/_base_device.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/_converters.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/_signal.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/core/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/_mover.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/testing/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/tango/testing/_test_config.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/_assert.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/_one_of_everything.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/_single_derived.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async.egg-info/requires.txt +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/src/ophyd_async.egg-info/top_level.txt +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/README.md +0 -0
- {ophyd_async-0.14.1/tests/unit_tests → ophyd_async-0.15/tests/system_tests}/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/conftest.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/adsim/baseline.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/adsim/external_dependencies.sh +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/adsim/test_adsim_system.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/eiger/README.md +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/eiger/test_eiger_system.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/signal/test_yaml_save_ca.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/epics/signal/test_yaml_save_pva.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/fastcs/panda/test_panda_connect.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests/test_tutorials.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests_tango/conftest.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests_tango/context_subprocess.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/system_tests_tango/test_base_device.py +0 -0
- {ophyd_async-0.14.1/tests/unit_tests/fastcs/jungfrau → ophyd_async-0.15/tests/unit_tests}/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_auto_init_devices.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_flyer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_log.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_protocol.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_providers.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_readable.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_signal.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_subset_enum.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_table.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/core/test_watchable_async_status.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adandor/test_andor.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adaravis/test_aravis.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_cont_acq_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_detectors.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_drivers.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_plugins.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_scans.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adcore/test_single_trigger.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adkinetix/test_kinetix.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adpilatus/test_pilatus.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/adsimdetector/test_sim.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/advimba/test_vimba.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/conftest.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pmac/conftest.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pmac/test_pmac_io.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pmac/test_pmac_trajectory_generation.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/pmac/test_pmac_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/signal/test_common.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/epics/test_areadetector_subclass_naming.py +0 -0
- {ophyd_async-0.14.1/tests/unit_tests/sim → ophyd_async-0.15/tests/unit_tests/fastcs/jungfrau}/__init__.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/jungfrau/test_controller.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/jungfrau/test_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/db/panda.db +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_hdf_panda.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_panda_connect_mock.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_panda_control.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_panda_utils.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_seq_table.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_trigger.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/fastcs/panda/test_writer.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/plan_stubs/test_ensure_connected.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/plan_stubs/test_fly.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/plan_stubs/test_setup.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/sim/test_sim_blob_detector.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/sim/test_sim_motor.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/test_branching.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/test_cli.py +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/test_data/test_yaml_config_save.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/tests/unit_tests/test_data/test_yaml_save.yaml +0 -0
- {ophyd_async-0.14.1 → ophyd_async-0.15}/uv.lock +0 -0
|
@@ -24,4 +24,4 @@ It is recommended that developers use a [vscode devcontainer](https://code.visua
|
|
|
24
24
|
|
|
25
25
|
This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects.
|
|
26
26
|
|
|
27
|
-
For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.
|
|
27
|
+
For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.2/how-to.html).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ophyd-async
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15
|
|
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
|
|
@@ -147,6 +147,7 @@ obj_ignore = [
|
|
|
147
147
|
"ophyd_async.core._device_filler.SignalBackendT",
|
|
148
148
|
"ophyd_async.core._device_filler.DeviceConnectorT",
|
|
149
149
|
"ophyd_async.core._derived_signal_backend.TransformT",
|
|
150
|
+
"ophyd_async.core._mock_signal_backend.MockPutCallback",
|
|
150
151
|
"ophyd_async.core._protocol.C",
|
|
151
152
|
"ophyd_async.core._signal_backend.SignalDatatypeV",
|
|
152
153
|
"ophyd_async.core._status.AsyncStatusBase",
|
|
@@ -164,8 +165,10 @@ obj_ignore = [
|
|
|
164
165
|
"ophyd_async.testing._utils.T",
|
|
165
166
|
"ophyd_async.sim._mirror.TwoJackRaw",
|
|
166
167
|
"ophyd_async.sim._mirror.TwoJackDerived",
|
|
168
|
+
"non_zero",
|
|
167
169
|
"0.1",
|
|
168
170
|
"1.0",
|
|
171
|
+
"bluesky.protocols.T_co",
|
|
169
172
|
]
|
|
170
173
|
nitpick_ignore = []
|
|
171
174
|
for var in obj_ignore:
|
|
@@ -43,16 +43,9 @@ To observe every value change and run a function on that value you can use [](#o
|
|
|
43
43
|
async for value in observe_value(signal):
|
|
44
44
|
do_something_with(value)
|
|
45
45
|
```
|
|
46
|
-
This will run until you `break` out of the loop.
|
|
46
|
+
This will run until you `break` out of the loop.
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
status = signal.set(value)
|
|
50
|
-
async for value in observe_value(signal2, done_status=status):
|
|
51
|
-
do_something_with(value)
|
|
52
|
-
# when signal.set() completes the loop will break out here
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
You can pass `timeout` to specify how the maximum time to wait for a single update, and `done_timeout` to specify the maximum time to wait for `done_status`.
|
|
48
|
+
You can pass `timeout` to specify the maximum time to wait for a single update.
|
|
56
49
|
|
|
57
50
|
If you want to wait for multiple signals you can use [](#observe_signals_value):
|
|
58
51
|
```python
|
|
@@ -63,6 +56,38 @@ async for signal, value in observe_value(signal1, signal2):
|
|
|
63
56
|
do_something_else_with(value)
|
|
64
57
|
```
|
|
65
58
|
|
|
59
|
+
## Use AsyncStatus as a context manager to bound loop execution
|
|
60
|
+
|
|
61
|
+
If you want a loop to run until some operation completes, you can use [](#AsyncStatus) as a context manager. When the status completes, it will cancel the calling task, causing the loop to exit. This is useful when you want to process signal updates until another operation finishes:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
# Process updates while a motor is moving
|
|
65
|
+
async with motor.set(target_position):
|
|
66
|
+
async for value in observe_value(detector):
|
|
67
|
+
process_reading(value)
|
|
68
|
+
# Loop automatically exits when motor reaches position
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If the loop completes before the status, the status task is automatically cancelled:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
async with signal1.set(new_value):
|
|
75
|
+
for i in range(3):
|
|
76
|
+
value = await signal.get_value()
|
|
77
|
+
process(value)
|
|
78
|
+
# Loop completes after 3 iterations, cancelling the wait for signal1 to finishe being set
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
If an exception is raised in the loop body, it propagates out normally:
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
async with signal1.set(new_value):
|
|
85
|
+
async for value in observe_value(signal2):
|
|
86
|
+
if value > threshold:
|
|
87
|
+
raise ValueError("Threshold exceeded")
|
|
88
|
+
# Exception propagates, status is cancelled and no longer waits for signal1 to finish being set
|
|
89
|
+
```
|
|
90
|
+
|
|
66
91
|
## Wait for the value to match some expected value
|
|
67
92
|
|
|
68
93
|
If you don't need to run code for every signal update, but just want to wait until the signal matches some expected value, you can use [](#wait_for_value):
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.15'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 15)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'g6ebd5ae5e'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""The building blocks for making devices."""
|
|
2
2
|
|
|
3
|
+
from ._datatypes import Array1D, DTypeScalar_co, Table, TableSubclass
|
|
3
4
|
from ._derived_signal import (
|
|
4
5
|
DerivedSignalFactory,
|
|
5
6
|
derived_signal_r,
|
|
@@ -23,7 +24,7 @@ from ._device import (
|
|
|
23
24
|
default_mock_class,
|
|
24
25
|
init_devices,
|
|
25
26
|
)
|
|
26
|
-
from ._device_filler import DeviceFiller
|
|
27
|
+
from ._device_filler import DeviceAnnotation, DeviceFiller
|
|
27
28
|
from ._enums import (
|
|
28
29
|
EnabledDisabled,
|
|
29
30
|
EnableDisable,
|
|
@@ -44,7 +45,15 @@ from ._mock_signal_utils import (
|
|
|
44
45
|
set_mock_value,
|
|
45
46
|
set_mock_values,
|
|
46
47
|
)
|
|
47
|
-
from ._protocol import
|
|
48
|
+
from ._protocol import (
|
|
49
|
+
AsyncConfigurable,
|
|
50
|
+
AsyncLocatable,
|
|
51
|
+
AsyncMovable,
|
|
52
|
+
AsyncPausable,
|
|
53
|
+
AsyncReadable,
|
|
54
|
+
AsyncStageable,
|
|
55
|
+
Watcher,
|
|
56
|
+
)
|
|
48
57
|
from ._providers import (
|
|
49
58
|
AutoIncrementFilenameProvider,
|
|
50
59
|
AutoIncrementingPathProvider,
|
|
@@ -86,8 +95,6 @@ from ._signal import (
|
|
|
86
95
|
walk_signal_sources,
|
|
87
96
|
)
|
|
88
97
|
from ._signal_backend import (
|
|
89
|
-
Array1D,
|
|
90
|
-
DTypeScalar_co,
|
|
91
98
|
Primitive,
|
|
92
99
|
SignalBackend,
|
|
93
100
|
SignalDatatype,
|
|
@@ -97,7 +104,6 @@ from ._signal_backend import (
|
|
|
97
104
|
)
|
|
98
105
|
from ._soft_signal_backend import SoftSignalBackend
|
|
99
106
|
from ._status import AsyncStatus, WatchableAsyncStatus, completed_status
|
|
100
|
-
from ._table import Table, TableSubclass
|
|
101
107
|
from ._utils import (
|
|
102
108
|
CALCULATE_TIMEOUT,
|
|
103
109
|
DEFAULT_TIMEOUT,
|
|
@@ -117,6 +123,7 @@ from ._utils import (
|
|
|
117
123
|
get_enum_cls,
|
|
118
124
|
get_unique,
|
|
119
125
|
in_micros,
|
|
126
|
+
non_zero,
|
|
120
127
|
wait_for_connection,
|
|
121
128
|
)
|
|
122
129
|
from ._yaml_settings import YamlSettingsProvider
|
|
@@ -146,11 +153,15 @@ __all__ = [
|
|
|
146
153
|
"Device",
|
|
147
154
|
"DeviceConnector",
|
|
148
155
|
"DeviceFiller",
|
|
156
|
+
"DeviceAnnotation",
|
|
149
157
|
"DeviceVector",
|
|
150
158
|
"init_devices",
|
|
151
159
|
# Protocols
|
|
152
160
|
"AsyncReadable",
|
|
153
161
|
"AsyncConfigurable",
|
|
162
|
+
"AsyncLocatable",
|
|
163
|
+
"AsyncMovable",
|
|
164
|
+
"AsyncPausable",
|
|
154
165
|
"AsyncStageable",
|
|
155
166
|
"Watcher",
|
|
156
167
|
# Status
|
|
@@ -255,6 +266,7 @@ __all__ = [
|
|
|
255
266
|
"make_datakey",
|
|
256
267
|
"wait_for_connection",
|
|
257
268
|
"Ignore",
|
|
269
|
+
"non_zero",
|
|
258
270
|
# Derived signal
|
|
259
271
|
"derived_signal_r",
|
|
260
272
|
"derived_signal_rw",
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable, Sequence
|
|
4
|
-
from typing import Annotated, Any, TypeVar
|
|
4
|
+
from typing import Annotated, Any, TypeVar
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from pydantic import ConfigDict, Field, model_validator
|
|
8
8
|
from pydantic_numpy.helper.annotation import NpArrayPydanticAnnotation
|
|
9
9
|
|
|
10
|
-
from ._utils import ConfinedModel, get_dtype
|
|
10
|
+
from ._utils import ConfinedModel, cached_get_origin, cached_get_type_hints, get_dtype
|
|
11
|
+
|
|
12
|
+
DTypeScalar_co = TypeVar("DTypeScalar_co", covariant=True, bound=np.generic)
|
|
13
|
+
"""A numpy dtype like [](#numpy.float64)."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# To be a 1D array shape should really be tuple[int], but np.array()
|
|
17
|
+
# currently produces tuple[int, ...] even when it has 1D input args
|
|
18
|
+
# https://github.com/numpy/numpy/issues/28077#issuecomment-2566485178
|
|
19
|
+
Array1D = np.ndarray[tuple[int, ...], np.dtype[DTypeScalar_co]]
|
|
20
|
+
"""A type alias for a 1D numpy array with a specific scalar data type.
|
|
21
|
+
|
|
22
|
+
E.g. `Array1D[np.float64]` is a 1D numpy array of 64-bit floats."""
|
|
11
23
|
|
|
12
24
|
TableSubclass = TypeVar("TableSubclass", bound="Table")
|
|
13
25
|
|
|
@@ -75,11 +87,8 @@ class Table(ConfinedModel):
|
|
|
75
87
|
# ...but forbid extra in subclasses so it gets validated
|
|
76
88
|
cls.model_config = ConfigDict(validate_assignment=True, extra="forbid")
|
|
77
89
|
# Change fields to have the correct annotations
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
for k, anno in get_type_hints(cls, localns={"Array1D": Array1D}).items():
|
|
82
|
-
if get_origin(anno) is np.ndarray:
|
|
90
|
+
for k, anno in cached_get_type_hints(cls).items():
|
|
91
|
+
if cached_get_origin(anno) is np.ndarray:
|
|
83
92
|
dtype = get_dtype(anno)
|
|
84
93
|
new_anno = Annotated[
|
|
85
94
|
anno,
|
|
@@ -88,7 +97,7 @@ class Table(ConfinedModel):
|
|
|
88
97
|
),
|
|
89
98
|
Field(default_factory=_make_default_factory(dtype)),
|
|
90
99
|
]
|
|
91
|
-
elif
|
|
100
|
+
elif cached_get_origin(anno) is Sequence:
|
|
92
101
|
new_anno = Annotated[anno, Field(default_factory=list)]
|
|
93
102
|
else:
|
|
94
103
|
raise TypeError(f"Cannot use annotation {anno} in a Table")
|
|
@@ -156,7 +165,7 @@ class Table(ConfinedModel):
|
|
|
156
165
|
raise AssertionError(f"Cannot construct Table from {data}")
|
|
157
166
|
for field_name, field_value in cls.model_fields.items():
|
|
158
167
|
if (
|
|
159
|
-
|
|
168
|
+
cached_get_origin(field_value.annotation) is np.ndarray
|
|
160
169
|
and field_value.annotation
|
|
161
170
|
and field_name in data_dict
|
|
162
171
|
):
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
from
|
|
1
|
+
import functools
|
|
2
|
+
from collections.abc import Awaitable, Callable, Mapping
|
|
3
|
+
from inspect import Parameter, signature
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
Generic,
|
|
7
|
+
TypeVar,
|
|
8
|
+
get_args,
|
|
9
|
+
get_origin,
|
|
10
|
+
is_typeddict,
|
|
11
|
+
)
|
|
3
12
|
|
|
4
13
|
from bluesky.protocols import Locatable
|
|
5
14
|
|
|
@@ -12,6 +21,7 @@ from ._derived_signal_backend import (
|
|
|
12
21
|
from ._device import Device
|
|
13
22
|
from ._signal import Signal, SignalR, SignalRW, SignalT, SignalW
|
|
14
23
|
from ._signal_backend import Primitive, SignalDatatypeT
|
|
24
|
+
from ._utils import cached_get_type_hints
|
|
15
25
|
|
|
16
26
|
|
|
17
27
|
class DerivedSignalFactory(Generic[TransformT]):
|
|
@@ -53,12 +63,13 @@ class DerivedSignalFactory(Generic[TransformT]):
|
|
|
53
63
|
# Populate expected parameters and types
|
|
54
64
|
expected = {
|
|
55
65
|
**{k: f.annotation for k, f in transform_cls.model_fields.items()},
|
|
56
|
-
**
|
|
57
|
-
k: v
|
|
58
|
-
for k, v in get_type_hints(transform_cls.raw_to_derived).items()
|
|
59
|
-
if k not in {"self", "return"}
|
|
60
|
-
},
|
|
66
|
+
**_get_params_types_dict(transform_cls.raw_to_derived),
|
|
61
67
|
}
|
|
68
|
+
if empty_keys := [k for k, v in expected.items() if v == Parameter.empty]:
|
|
69
|
+
raise TypeError(
|
|
70
|
+
f"{transform_cls.raw_to_derived} is missing a type "
|
|
71
|
+
f"hint for arguments: {empty_keys}"
|
|
72
|
+
)
|
|
62
73
|
|
|
63
74
|
# Populate received parameters and types
|
|
64
75
|
# Use Primitive's type, Signal's datatype,
|
|
@@ -76,7 +87,19 @@ class DerivedSignalFactory(Generic[TransformT]):
|
|
|
76
87
|
f"Expected the following to be passed as keyword arguments "
|
|
77
88
|
f"{expected}, got {received}"
|
|
78
89
|
)
|
|
79
|
-
|
|
90
|
+
if set(expected.keys()) - set(received.keys()):
|
|
91
|
+
raise TypeError(msg)
|
|
92
|
+
|
|
93
|
+
for k in set(expected.keys()):
|
|
94
|
+
if isinstance(expected[k], type):
|
|
95
|
+
if not issubclass(received[k], expected[k]):
|
|
96
|
+
raise TypeError(msg)
|
|
97
|
+
elif isinstance(expected[k], TypeVar):
|
|
98
|
+
bound = expected[k].__bound__
|
|
99
|
+
if isinstance(bound, type) and not issubclass(
|
|
100
|
+
received[k], bound
|
|
101
|
+
):
|
|
102
|
+
raise TypeError(msg)
|
|
80
103
|
self._set_derived_takes_dict = (
|
|
81
104
|
is_typeddict(_get_first_arg_datatype(set_derived)) if set_derived else False
|
|
82
105
|
)
|
|
@@ -185,7 +208,7 @@ class DerivedSignalFactory(Generic[TransformT]):
|
|
|
185
208
|
|
|
186
209
|
|
|
187
210
|
def _get_return_datatype(func: Callable[..., SignalDatatypeT]) -> type[SignalDatatypeT]:
|
|
188
|
-
args =
|
|
211
|
+
args = cached_get_type_hints(func)
|
|
189
212
|
if "return" not in args:
|
|
190
213
|
msg = f"{func} does not have a type hint for it's return value"
|
|
191
214
|
raise TypeError(msg)
|
|
@@ -195,28 +218,28 @@ def _get_return_datatype(func: Callable[..., SignalDatatypeT]) -> type[SignalDat
|
|
|
195
218
|
def _get_first_arg_datatype(
|
|
196
219
|
func: Callable[[SignalDatatypeT], Any],
|
|
197
220
|
) -> type[SignalDatatypeT]:
|
|
198
|
-
args =
|
|
199
|
-
args.pop("return", None)
|
|
221
|
+
args = _get_params_types_dict(func)
|
|
200
222
|
if not args:
|
|
201
223
|
msg = f"{func} does not have a type hinted argument"
|
|
202
224
|
raise TypeError(msg)
|
|
203
225
|
return list(args.values())[0]
|
|
204
226
|
|
|
205
227
|
|
|
228
|
+
def _get_params_types_dict(inspected_function: Callable) -> Mapping[str, Any]:
|
|
229
|
+
sig = signature(inspected_function, eval_str=True)
|
|
230
|
+
exclude_keys = {"self", "args", "kwargs", "cls"}
|
|
231
|
+
return {k: v.annotation for k, v in sig.parameters.items() if k not in exclude_keys}
|
|
232
|
+
|
|
233
|
+
|
|
206
234
|
def _make_factory(
|
|
207
|
-
|
|
235
|
+
raw_to_derived_func: Callable[..., SignalDatatypeT] | None = None,
|
|
208
236
|
set_derived: Callable[[SignalDatatypeT], Awaitable[None]] | None = None,
|
|
209
237
|
raw_devices_and_constants: dict[str, Device | Primitive] | None = None,
|
|
210
238
|
) -> DerivedSignalFactory:
|
|
211
|
-
if
|
|
239
|
+
if raw_to_derived_func:
|
|
212
240
|
|
|
213
241
|
class DerivedTransform(Transform):
|
|
214
|
-
|
|
215
|
-
return {"value": raw_to_derived(**kwargs)}
|
|
216
|
-
|
|
217
|
-
# Update the signature for raw_to_derived to match what we are passed as this
|
|
218
|
-
# will be checked in DerivedSignalFactory
|
|
219
|
-
DerivedTransform.raw_to_derived.__annotations__ = get_type_hints(raw_to_derived)
|
|
242
|
+
raw_to_derived = _dict_wrapper(raw_to_derived_func)
|
|
220
243
|
|
|
221
244
|
return DerivedSignalFactory(
|
|
222
245
|
DerivedTransform,
|
|
@@ -245,7 +268,7 @@ def derived_signal_r(
|
|
|
245
268
|
The names of these arguments must match the arguments of raw_to_derived.
|
|
246
269
|
"""
|
|
247
270
|
factory = _make_factory(
|
|
248
|
-
|
|
271
|
+
raw_to_derived_func=raw_to_derived,
|
|
249
272
|
raw_devices_and_constants=raw_devices_and_constants,
|
|
250
273
|
)
|
|
251
274
|
return factory.derived_signal_r(
|
|
@@ -278,16 +301,16 @@ def derived_signal_rw(
|
|
|
278
301
|
The names of these arguments must match the arguments of raw_to_derived.
|
|
279
302
|
"""
|
|
280
303
|
raw_to_derived_datatype = _get_return_datatype(raw_to_derived)
|
|
281
|
-
|
|
282
|
-
if raw_to_derived_datatype !=
|
|
304
|
+
set_derived_arg_datatype = _get_first_arg_datatype(set_derived)
|
|
305
|
+
if raw_to_derived_datatype != set_derived_arg_datatype:
|
|
283
306
|
msg = (
|
|
284
307
|
f"{raw_to_derived} has datatype {raw_to_derived_datatype} "
|
|
285
|
-
f"!= {
|
|
308
|
+
f"!= {set_derived_arg_datatype} datatype {set_derived_arg_datatype}"
|
|
286
309
|
)
|
|
287
310
|
raise TypeError(msg)
|
|
288
311
|
|
|
289
312
|
factory = _make_factory(
|
|
290
|
-
|
|
313
|
+
raw_to_derived_func=raw_to_derived,
|
|
291
314
|
set_derived=set_derived,
|
|
292
315
|
raw_devices_and_constants=raw_devices_and_constants,
|
|
293
316
|
)
|
|
@@ -343,3 +366,13 @@ def _partition_by_keys(data: dict, keys: set) -> tuple[dict, dict]:
|
|
|
343
366
|
else:
|
|
344
367
|
group_excluded[k] = v
|
|
345
368
|
return group_excluded, group_included
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _dict_wrapper(
|
|
372
|
+
fn: Callable[..., SignalDatatypeT],
|
|
373
|
+
) -> Callable[..., dict[str, SignalDatatypeT]]:
|
|
374
|
+
@functools.wraps(fn)
|
|
375
|
+
def wrapped(self, **kwargs):
|
|
376
|
+
return {"value": fn(**kwargs)}
|
|
377
|
+
|
|
378
|
+
return wrapped
|
|
@@ -291,11 +291,7 @@ class DerivedSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
|
291
291
|
)
|
|
292
292
|
raise RuntimeError(msg)
|
|
293
293
|
|
|
294
|
-
async def put(self, value: SignalDatatypeT | None
|
|
295
|
-
if wait is False:
|
|
296
|
-
msg = "Cannot put with wait=False"
|
|
297
|
-
raise RuntimeError(msg)
|
|
298
|
-
|
|
294
|
+
async def put(self, value: SignalDatatypeT | None) -> None:
|
|
299
295
|
value = error_if_none(
|
|
300
296
|
value,
|
|
301
297
|
"Must be given a value to put",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import types
|
|
3
4
|
from abc import abstractmethod
|
|
4
5
|
from collections.abc import Callable, Iterator, Sequence
|
|
5
6
|
from typing import (
|
|
@@ -9,16 +10,16 @@ from typing import (
|
|
|
9
10
|
NoReturn,
|
|
10
11
|
Protocol,
|
|
11
12
|
TypeVar,
|
|
13
|
+
Union,
|
|
12
14
|
cast,
|
|
13
15
|
get_args,
|
|
14
|
-
get_type_hints,
|
|
15
16
|
runtime_checkable,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
from ._device import Device, DeviceConnector, DeviceVector
|
|
19
20
|
from ._signal import Ignore, Signal, SignalX
|
|
20
21
|
from ._signal_backend import SignalBackend, SignalDatatype
|
|
21
|
-
from ._utils import get_origin_class
|
|
22
|
+
from ._utils import cached_get_origin, cached_get_type_hints, get_origin_class
|
|
22
23
|
|
|
23
24
|
SignalBackendT = TypeVar("SignalBackendT", bound=SignalBackend)
|
|
24
25
|
DeviceConnectorT = TypeVar("DeviceConnectorT", bound=DeviceConnector)
|
|
@@ -76,6 +77,7 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
|
|
|
76
77
|
self._extras: dict[UniqueName, Sequence[Any]] = {}
|
|
77
78
|
self._signal_datatype: dict[LogicalName, type | None] = {}
|
|
78
79
|
self._vector_device_type: dict[LogicalName, type[Device] | None] = {}
|
|
80
|
+
self._optional_devices: set[str] = set()
|
|
79
81
|
self.ignored_signals: set[str] = set()
|
|
80
82
|
# Backends and Connectors stored ready for the connection phase
|
|
81
83
|
self._unfilled_backends: dict[
|
|
@@ -113,14 +115,28 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
|
|
|
113
115
|
# https://github.com/python/cpython/issues/124840
|
|
114
116
|
cls = type(self._device)
|
|
115
117
|
# Get hints without Annotated for determining types
|
|
116
|
-
hints =
|
|
118
|
+
hints = cached_get_type_hints(cls)
|
|
117
119
|
# Get hints with Annotated for wrapping signals and backends
|
|
118
|
-
extra_hints =
|
|
120
|
+
extra_hints = cached_get_type_hints(cls, include_extras=True)
|
|
119
121
|
for attr_name, annotation in hints.items():
|
|
120
122
|
if annotation is Ignore:
|
|
121
123
|
self.ignored_signals.add(attr_name)
|
|
122
124
|
name = UniqueName(attr_name)
|
|
123
125
|
origin = get_origin_class(annotation)
|
|
126
|
+
args = get_args(annotation)
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
cached_get_origin(annotation) is Union
|
|
130
|
+
and types.NoneType in args
|
|
131
|
+
and len(args) == 2
|
|
132
|
+
):
|
|
133
|
+
# Annotation is an Union with two arguments, one of which is None
|
|
134
|
+
# Make this signal an optional parameter and set origin to T
|
|
135
|
+
# so the device is added to unfilled_connectors
|
|
136
|
+
self._optional_devices.add(name)
|
|
137
|
+
(annotation,) = [x for x in args if x is not types.NoneType]
|
|
138
|
+
origin = get_origin_class(annotation)
|
|
139
|
+
|
|
124
140
|
if (
|
|
125
141
|
name == "parent"
|
|
126
142
|
or name.startswith("_")
|
|
@@ -241,10 +257,17 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
|
|
|
241
257
|
:param source: The source of the data that should have done the filling, for
|
|
242
258
|
reporting as an error message
|
|
243
259
|
"""
|
|
244
|
-
unfilled =
|
|
245
|
-
|
|
260
|
+
unfilled = set(self._unfilled_connectors).union(self._unfilled_backends)
|
|
261
|
+
unfilled_optional = sorted(unfilled.intersection(self._optional_devices))
|
|
262
|
+
|
|
263
|
+
for name in unfilled_optional:
|
|
264
|
+
setattr(self._device, name, None)
|
|
265
|
+
|
|
266
|
+
required = sorted(unfilled.difference(unfilled_optional))
|
|
267
|
+
|
|
268
|
+
if required:
|
|
246
269
|
raise RuntimeError(
|
|
247
|
-
f"{self._device.name}: cannot provision {
|
|
270
|
+
f"{self._device.name}: cannot provision {required} from {source}"
|
|
248
271
|
)
|
|
249
272
|
|
|
250
273
|
def _ensure_device_vector(self, name: LogicalName) -> DeviceVector:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
from collections.abc import Callable
|
|
4
|
+
from collections.abc import Awaitable, Callable
|
|
5
5
|
from functools import cached_property
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
from unittest.mock import AsyncMock
|
|
@@ -17,6 +17,11 @@ from ._utils import Callback
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from ._device import LazyMock
|
|
19
19
|
|
|
20
|
+
MockPutCallback = (
|
|
21
|
+
Callable[[SignalDatatypeT], SignalDatatypeT | None]
|
|
22
|
+
| Callable[[SignalDatatypeT], Awaitable[SignalDatatypeT | None]]
|
|
23
|
+
)
|
|
24
|
+
|
|
20
25
|
|
|
21
26
|
class MockSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
22
27
|
"""Signal backend for testing, created by ``Device.connect(mock=True)``."""
|
|
@@ -42,13 +47,27 @@ class MockSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
|
42
47
|
|
|
43
48
|
# use existing Mock if provided
|
|
44
49
|
self.mock = mock
|
|
50
|
+
self._mock_put_callback: MockPutCallback | None = None
|
|
45
51
|
super().__init__(datatype=self.initial_backend.datatype)
|
|
46
52
|
|
|
53
|
+
def set_mock_put_callback(self, callback: MockPutCallback | None):
|
|
54
|
+
if "put_mock" in self.__dict__:
|
|
55
|
+
# put_mock cached property exists, so set the side effect on it
|
|
56
|
+
self.put_mock.side_effect = callback
|
|
57
|
+
else:
|
|
58
|
+
# put_mock doesn't exist, don't create it as that would be slow
|
|
59
|
+
# so just keep it internally
|
|
60
|
+
self._mock_put_callback = callback
|
|
61
|
+
|
|
47
62
|
@cached_property
|
|
48
63
|
def put_mock(self) -> AsyncMock:
|
|
49
64
|
"""Return the mock that will track calls to `put()`."""
|
|
50
65
|
put_mock = AsyncMock(
|
|
51
|
-
name="put",
|
|
66
|
+
name="put",
|
|
67
|
+
spec=Callable,
|
|
68
|
+
side_effect=self._mock_put_callback
|
|
69
|
+
if self._mock_put_callback
|
|
70
|
+
else lambda v: None,
|
|
52
71
|
)
|
|
53
72
|
self.mock().attach_mock(put_mock, "put")
|
|
54
73
|
return put_mock
|
|
@@ -73,13 +92,12 @@ class MockSignalBackend(SignalBackend[SignalDatatypeT]):
|
|
|
73
92
|
put_proceeds.set()
|
|
74
93
|
return put_proceeds
|
|
75
94
|
|
|
76
|
-
async def put(self, value: SignalDatatypeT | None
|
|
77
|
-
new_value = await self.put_mock(value
|
|
95
|
+
async def put(self, value: SignalDatatypeT | None):
|
|
96
|
+
new_value = await self.put_mock(value)
|
|
78
97
|
if new_value is None:
|
|
79
98
|
new_value = value
|
|
80
|
-
await self.soft_backend.put(new_value
|
|
81
|
-
|
|
82
|
-
await self.put_proceeds.wait()
|
|
99
|
+
await self.soft_backend.put(new_value)
|
|
100
|
+
await self.put_proceeds.wait()
|
|
83
101
|
|
|
84
102
|
async def get_reading(self) -> Reading:
|
|
85
103
|
return await self.soft_backend.get_reading()
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
from collections.abc import
|
|
1
|
+
from collections.abc import Iterable, Iterator
|
|
2
2
|
from contextlib import contextmanager
|
|
3
3
|
from unittest.mock import AsyncMock, Mock
|
|
4
4
|
|
|
5
5
|
from ._device import Device, DeviceMock
|
|
6
|
-
from ._mock_signal_backend import MockSignalBackend
|
|
6
|
+
from ._mock_signal_backend import MockPutCallback, MockSignalBackend
|
|
7
7
|
from ._signal import Signal, SignalConnector, SignalR
|
|
8
8
|
from ._signal_backend import SignalDatatypeT
|
|
9
9
|
|
|
@@ -109,16 +109,12 @@ def set_mock_values(
|
|
|
109
109
|
|
|
110
110
|
|
|
111
111
|
@contextmanager
|
|
112
|
-
def _unset_side_effect_cm(
|
|
112
|
+
def _unset_side_effect_cm(backend: MockSignalBackend):
|
|
113
113
|
yield
|
|
114
|
-
|
|
114
|
+
backend.set_mock_put_callback(None)
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
def callback_on_mock_put(
|
|
118
|
-
signal: Signal[SignalDatatypeT],
|
|
119
|
-
callback: Callable[[SignalDatatypeT, bool], SignalDatatypeT | None]
|
|
120
|
-
| Callable[[SignalDatatypeT, bool], Awaitable[SignalDatatypeT | None]],
|
|
121
|
-
):
|
|
117
|
+
def callback_on_mock_put(signal: Signal[SignalDatatypeT], callback: MockPutCallback):
|
|
122
118
|
"""For setting a callback when a backend is put to.
|
|
123
119
|
|
|
124
120
|
Can either be used in a context, with the callback being unset on exit, or
|
|
@@ -132,8 +128,8 @@ def callback_on_mock_put(
|
|
|
132
128
|
context.
|
|
133
129
|
"""
|
|
134
130
|
backend = _get_mock_signal_backend(signal)
|
|
135
|
-
backend.
|
|
136
|
-
return _unset_side_effect_cm(backend
|
|
131
|
+
backend.set_mock_put_callback(callback)
|
|
132
|
+
return _unset_side_effect_cm(backend)
|
|
137
133
|
|
|
138
134
|
|
|
139
135
|
def set_mock_put_proceeds(signal: Signal, proceeds: bool):
|