ophyd-async 0.8.0a4__tar.gz → 0.8.0a6__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.
Files changed (252) hide show
  1. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/PKG-INFO +1 -1
  2. ophyd_async-0.8.0a6/docs/how-to/use_set_and_wait_for_other_value.md +45 -0
  3. ophyd_async-0.8.0a6/docs/images/set_and_wait_for_other_value.svg +10 -0
  4. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/_version.py +1 -1
  5. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/__init__.py +2 -0
  6. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_device.py +9 -2
  7. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_signal.py +86 -16
  8. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_soft_signal_backend.py +6 -2
  9. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_table.py +9 -4
  10. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_utils.py +24 -19
  11. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/_core_logic.py +3 -1
  12. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_aioca.py +1 -1
  13. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_p4p.py +1 -0
  14. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/eiger/_eiger_controller.py +6 -1
  15. ophyd_async-0.8.0a6/src/ophyd_async/epics/testing/__init__.py +24 -0
  16. ophyd_async-0.8.0a6/src/ophyd_async/epics/testing/_example_ioc.py +105 -0
  17. ophyd_async-0.8.0a6/src/ophyd_async/epics/testing/_utils.py +78 -0
  18. ophyd_async-0.8.0a6/src/ophyd_async/epics/testing/test_records.db +152 -0
  19. ophyd_async-0.8.0a6/src/ophyd_async/epics/testing/test_records_pva.db +177 -0
  20. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_table.py +1 -1
  21. ophyd_async-0.8.0a6/src/ophyd_async/plan_stubs/_ensure_connected.py +33 -0
  22. {ophyd_async-0.8.0a4/src/ophyd_async/tango/signal → ophyd_async-0.8.0a6/src/ophyd_async/tango/core}/__init__.py +7 -2
  23. {ophyd_async-0.8.0a4/src/ophyd_async/tango/base_devices → ophyd_async-0.8.0a6/src/ophyd_async/tango/core}/_base_device.py +38 -64
  24. {ophyd_async-0.8.0a4/src/ophyd_async/tango/signal → ophyd_async-0.8.0a6/src/ophyd_async/tango/core}/_signal.py +13 -3
  25. {ophyd_async-0.8.0a4/src/ophyd_async/tango/base_devices → ophyd_async-0.8.0a6/src/ophyd_async/tango/core}/_tango_readable.py +3 -4
  26. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/_counter.py +6 -7
  27. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/_mover.py +8 -7
  28. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/PKG-INFO +1 -1
  29. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/SOURCES.txt +13 -7
  30. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_device.py +5 -0
  31. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_device_save_loader.py +27 -64
  32. ophyd_async-0.8.0a6/tests/core/test_observe.py +117 -0
  33. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_signal.py +82 -25
  34. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_soft_signal_backend.py +12 -15
  35. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_utils.py +32 -0
  36. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/signal/test_signals.py +267 -270
  37. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_hdf_panda.py +1 -1
  38. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_trigger.py +1 -1
  39. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_writer.py +4 -4
  40. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/plan_stubs/test_ensure_connected.py +14 -0
  41. ophyd_async-0.8.0a6/tests/sim/demo/__init__.py +0 -0
  42. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/tango/test_base_device.py +1 -1
  43. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/tango/test_tango_signals.py +1 -1
  44. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/tango/test_tango_transport.py +1 -1
  45. ophyd_async-0.8.0a6/tests/test_data/test_yaml_save.yml +40 -0
  46. ophyd_async-0.8.0a4/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -26
  47. ophyd_async-0.8.0a4/src/ophyd_async/tango/__init__.py +0 -43
  48. ophyd_async-0.8.0a4/src/ophyd_async/tango/base_devices/__init__.py +0 -4
  49. ophyd_async-0.8.0a4/tests/epics/signal/test_records.db +0 -330
  50. ophyd_async-0.8.0a4/tests/test_data/test_yaml_save.yml +0 -47
  51. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.codecov.yml +0 -0
  52. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.copier-answers.yml +0 -0
  53. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.devcontainer/devcontainer.json +0 -0
  54. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.git-blame-ignore-revs +0 -0
  55. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/CONTRIBUTING.md +0 -0
  56. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  57. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  58. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  59. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/actions/install_requirements/action.yml +0 -0
  60. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/dependabot.yml +0 -0
  61. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/pages/index.html +0 -0
  62. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/pages/make_switcher.py +0 -0
  63. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_check.yml +0 -0
  64. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_dist.yml +0 -0
  65. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_docs.yml +0 -0
  66. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_pypi.yml +0 -0
  67. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_release.yml +0 -0
  68. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_test.yml +0 -0
  69. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/_tox.yml +0 -0
  70. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/ci.yml +0 -0
  71. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.github/workflows/periodic.yml +0 -0
  72. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.gitignore +0 -0
  73. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.mailmap +0 -0
  74. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/.pre-commit-config.yaml +0 -0
  75. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/Dockerfile +0 -0
  76. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/LICENSE +0 -0
  77. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/README.md +0 -0
  78. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/_api.rst +0 -0
  79. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/_templates/custom-module-template.rst +0 -0
  80. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/conf.py +0 -0
  81. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/examples/epics_demo.py +0 -0
  82. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/examples/foo_detector.py +0 -0
  83. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/examples/tango_demo.py +0 -0
  84. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  85. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  86. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  87. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  88. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  89. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  90. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  91. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0008-signal-types.md +0 -0
  92. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  93. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions/COPYME +0 -0
  94. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/decisions.md +0 -0
  95. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/design-goals.rst +0 -0
  96. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/event-loop-choice.rst +0 -0
  97. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations/flyscanning.rst +0 -0
  98. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/explanations.md +0 -0
  99. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/genindex.rst +0 -0
  100. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/choose-interfaces-for-devices.md +0 -0
  101. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/compound-devices.rst +0 -0
  102. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/contribute.md +0 -0
  103. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/make-a-simple-device.rst +0 -0
  104. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/make-a-standard-detector.rst +0 -0
  105. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to/write-tests-for-devices.rst +0 -0
  106. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/how-to.md +0 -0
  107. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/images/ophyd-async-logo.svg +0 -0
  108. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/images/ophyd-favicon.svg +0 -0
  109. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/index.md +0 -0
  110. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/reference.md +0 -0
  111. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/tutorials/installation.md +0 -0
  112. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/tutorials/using-existing-devices.rst +0 -0
  113. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/docs/tutorials.md +0 -0
  114. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/pyproject.toml +0 -0
  115. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/setup.cfg +0 -0
  116. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/__init__.py +0 -0
  117. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/__main__.py +0 -0
  118. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_detector.py +0 -0
  119. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_device_filler.py +0 -0
  120. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_device_save_loader.py +0 -0
  121. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_flyer.py +0 -0
  122. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_hdf_dataset.py +0 -0
  123. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_log.py +0 -0
  124. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  125. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_mock_signal_utils.py +0 -0
  126. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_protocol.py +0 -0
  127. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_providers.py +0 -0
  128. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_readable.py +0 -0
  129. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_signal_backend.py +0 -0
  130. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/core/_status.py +0 -0
  131. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/__init__.py +0 -0
  132. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  133. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  134. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
  135. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  136. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  137. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  138. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
  139. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  140. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  141. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  142. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  143. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  144. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  145. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  146. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  147. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  148. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  149. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  150. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  151. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  152. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  153. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  154. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
  155. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  156. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/__init__.py +0 -0
  157. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  158. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  159. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  160. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_signal.py +0 -0
  161. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/core/_util.py +0 -0
  162. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/demo/__init__.py +0 -0
  163. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/demo/_mover.py +0 -0
  164. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/demo/_sensor.py +0 -0
  165. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/demo/mover.db +0 -0
  166. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/demo/sensor.db +0 -0
  167. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/eiger/__init__.py +0 -0
  168. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/eiger/_eiger.py +0 -0
  169. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/eiger/_eiger_io.py +0 -0
  170. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/eiger/_odin_io.py +0 -0
  171. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/motor.py +0 -0
  172. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/epics/signal.py +0 -0
  173. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/__init__.py +0 -0
  174. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/core.py +0 -0
  175. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  176. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  177. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_block.py +0 -0
  178. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  179. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  180. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
  181. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_utils.py +0 -0
  182. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
  183. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  184. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  185. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  186. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/py.typed +0 -0
  187. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/__init__.py +0 -0
  188. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/__init__.py +0 -0
  189. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_pattern_detector/__init__.py +0 -0
  190. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector.py +0 -0
  191. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector_controller.py +0 -0
  192. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_detector_writer.py +0 -0
  193. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_pattern_detector/_pattern_generator.py +0 -0
  194. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/demo/_sim_motor.py +0 -0
  195. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/sim/testing/__init__.py +0 -0
  196. {ophyd_async-0.8.0a4/tests/sim → ophyd_async-0.8.0a6/src/ophyd_async/tango}/__init__.py +0 -0
  197. {ophyd_async-0.8.0a4/src/ophyd_async/tango/signal → ophyd_async-0.8.0a6/src/ophyd_async/tango/core}/_tango_transport.py +0 -0
  198. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/__init__.py +0 -0
  199. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/_detector.py +0 -0
  200. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  201. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  202. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  203. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/entry_points.txt +0 -0
  204. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/requires.txt +0 -0
  205. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/src/ophyd_async.egg-info/top_level.txt +0 -0
  206. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/system_tests/epics/eiger/README.md +0 -0
  207. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  208. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/system_tests/epics/eiger/test_eiger_system.py +0 -0
  209. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/conftest.py +0 -0
  210. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_device_collector.py +0 -0
  211. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_flyer.py +0 -0
  212. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_log.py +0 -0
  213. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_mock_signal_backend.py +0 -0
  214. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_protocol.py +0 -0
  215. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_providers.py +0 -0
  216. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_readable.py +0 -0
  217. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_status.py +0 -0
  218. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_subset_enum.py +0 -0
  219. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_table.py +0 -0
  220. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/core/test_watchable_async_status.py +0 -0
  221. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adaravis/test_aravis.py +0 -0
  222. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adcore/test_drivers.py +0 -0
  223. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adcore/test_scans.py +0 -0
  224. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adcore/test_single_trigger.py +0 -0
  225. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adcore/test_writers.py +0 -0
  226. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adkinetix/test_kinetix.py +0 -0
  227. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adpilatus/test_pilatus.py +0 -0
  228. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/adsimdetector/test_sim.py +0 -0
  229. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/advimba/test_vimba.py +0 -0
  230. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/conftest.py +0 -0
  231. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/demo/test_demo.py +0 -0
  232. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/eiger/test_eiger_controller.py +0 -0
  233. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/eiger/test_eiger_detector.py +0 -0
  234. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/eiger/test_odin_io.py +0 -0
  235. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/pvi/test_pvi.py +0 -0
  236. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/signal/test_common.py +0 -0
  237. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/test_areadetector_subclass_naming.py +0 -0
  238. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/epics/test_motor.py +0 -0
  239. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/db/panda.db +0 -0
  240. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_panda_connect.py +0 -0
  241. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_panda_control.py +0 -0
  242. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_panda_utils.py +0 -0
  243. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/fastcs/panda/test_seq_table.py +0 -0
  244. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/plan_stubs/test_fly.py +0 -0
  245. {ophyd_async-0.8.0a4/tests/sim/demo → ophyd_async-0.8.0a6/tests/sim}/__init__.py +0 -0
  246. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/conftest.py +0 -0
  247. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/demo/test_sim_motor.py +0 -0
  248. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/test_pattern_generator.py +0 -0
  249. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/test_sim_detector.py +0 -0
  250. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/test_sim_writer.py +0 -0
  251. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/sim/test_streaming_plan.py +0 -0
  252. {ophyd_async-0.8.0a4 → ophyd_async-0.8.0a6}/tests/test_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.8.0a4
3
+ Version: 0.8.0a6
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
@@ -0,0 +1,45 @@
1
+ # `set_and_wait_for_other_value`
2
+
3
+ The `set_and_wait_for_other_value` function (defined in `_signal.py`) is a utility designed to:
4
+
5
+ 1. **Set a signal**.
6
+ 2. **Wait for another signal to reach a specified value (`match_value`)**.
7
+
8
+ The behavior of the function depends on the value of the `wait_for_set_completion` parameter:
9
+
10
+ - **If `wait_for_set_completion = True`:**
11
+ The function returns at **1** (see diagram below), which occurs when the "set operation" is complete.
12
+
13
+ - **If `wait_for_set_completion = False`:**
14
+ The function returns at **2**, which occurs when the `match_signal` reaches the `match_value`.
15
+
16
+ In **AreaDetector**, the `wait_for_set_completion` parameter should generally be set to **`False`**, as the preferred behavior is to return when the `match_signal` achieves the `match_value`.
17
+
18
+ ---
19
+
20
+ ## Behavior Diagram:
21
+
22
+ ![wait_for_set_completion](../images/set_and_wait_for_other_value.svg)
23
+
24
+ ---
25
+
26
+ ## Example Usage
27
+
28
+ ```python
29
+ # Example code snippet for using set_and_wait_for_other_value in an AreaDetector driver
30
+ self._arm_status = set_and_wait_for_other_value(
31
+ self._drv.arm,
32
+ 1,
33
+ self._drv.state,
34
+ "ready",
35
+ timeout=DEFAULT_TIMEOUT,
36
+ wait_for_set_completion=False,
37
+ )
38
+ ```
39
+
40
+ In this **AreaDetector driver**, the function ensures that the detector's `arm_status` reaches `"ready"` before capturing data. To achieve this:
41
+
42
+ - The detector is instructed to transition to the "armed" state by setting the driver's `arm` signal to `1`.
43
+ - The function waits until the driver's `state` signal equals `"ready"`.
44
+
45
+ This approach ensures that data capture is only initiated once the detector is fully prepared.
@@ -0,0 +1,10 @@
1
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1187.8240472771774 784.5838303364346" width="1187.8240472771774" height="784.5838303364346">
2
+ <!-- svg-source:excalidraw -->
3
+
4
+ <defs>
5
+ <style class="style-fonts">
6
+ @font-face { font-family: Excalifont; src: url(data:font/woff2;base64,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); }
7
+ </style>
8
+
9
+ </defs>
10
+ <rect x="0" y="0" width="1187.8240472771774" height="784.5838303364346" fill="#ffffff"></rect><g stroke-linecap="round"><g transform="translate(43.84248105120804 302.75444427692025) rotate(0 109.31598350459507 0)"><path d="M-0.45 -0.7 C35.76 -0.86, 180.92 -1.39, 217.58 -1.19 M1.51 1.54 C38.06 1.51, 183.45 0.24, 219.75 -0.28" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(262.4744480603982 302.8253415087969) rotate(0 0 -82.9293667965893)"><path d="M0.64 0.3 C0.59 -27.08, -0.08 -137.51, -0.32 -165.29 M-0.48 -0.59 C-0.72 -28.23, -1.79 -139.66, -1.44 -167.12" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(258.8706526177911 134.14839879518058) rotate(0 332.5798441252804 -1.9202069522244898)"><path d="M-0.18 0.98 C110.67 0.28, 554.82 -2.97, 665.76 -3.76 M-1.73 0.45 C108.95 -0.07, 554.04 -1.71, 665.12 -2.18" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(925.5665064301318 131.8441504525112) rotate(0 1.1521241713346626 80.10711520276767)"><path d="M0.54 0.53 C0.98 27.16, 1.63 133.33, 2.07 159.95 M-0.63 -0.24 C-0.32 26.56, 0.42 134.38, 1 161.35" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(926.3345892110212 293.1415344393678) rotate(0 68.92542750440384 -1.152124171334691)"><path d="M1.09 -0.33 C24.12 -0.33, 115.62 -0.86, 138.29 -1.2 M0.21 -1.54 C23.1 -1.75, 114.33 -2.82, 137.57 -2.74" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(154.08449781789392 67.15748673767692) rotate(0 52.98975332972128 33.34186726364484)"><path d="M-1.06 0.7 C16.59 11.86, 88.97 56.89, 106.91 67.72 M0.58 0.03 C18.07 10.8, 88.85 55.06, 106.45 66.14" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(154.08449781789392 67.15748673767692) rotate(0 52.98975332972128 33.34186726364484)"><path d="M82 60.91 C92.6 64.68, 102.53 66.17, 106.45 66.14 M82 60.91 C86.56 61.38, 93.31 62.59, 106.45 66.14" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(154.08449781789392 67.15748673767692) rotate(0 52.98975332972128 33.34186726364484)"><path d="M91.08 46.42 C98.28 55.67, 104.73 62.72, 106.45 66.14 M91.08 46.42 C93.64 50.1, 98.42 54.45, 106.45 66.14" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g transform="translate(73.11139160618495 10) rotate(0 47.0625 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">set called</text></g><g stroke-linecap="round"><g transform="translate(931.6644736450401 312.4583673202069) rotate(0 4.167733407955666 192.31112725280877)"><path d="M-0.34 -0.98 C1.13 63.35, 6.73 321.09, 8.05 385.17 M1.68 1.12 C3.03 65.16, 5.56 319.49, 6.94 383.33" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(931.6644736450401 312.4583673202069) rotate(0 4.167733407955666 192.31112725280877)"><path d="M-1.96 359.97 C-1.66 365.01, 2.98 369.66, 6.94 383.33 M-1.96 359.97 C0.77 365.61, 2.46 369.39, 6.94 383.33" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(931.6644736450401 312.4583673202069) rotate(0 4.167733407955666 192.31112725280877)"><path d="M15.14 359.71 C11.41 364.76, 12.02 369.48, 6.94 383.33 M15.14 359.71 C14.41 365.37, 12.64 369.21, 6.94 383.33" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g transform="translate(889.4853986759654 715.0686100052003) rotate(0 66.3862760711362 24.140464025867686)"><text x="0" y="17.014199045431567" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="19.312371220694175px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Set completed</text><text x="0" y="41.15466307129928" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="19.312371220694175px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic"></text></g><g stroke-linecap="round"><g transform="translate(45.723429211048085 551.6184165698157) rotate(0 208.3866703977804 -2.9769524342540308)"><path d="M1.15 -0.09 C70.36 -1.4, 346.52 -5.76, 415.96 -6.64 M0.29 -1.19 C69.83 -1.84, 348.7 -4.42, 418.24 -5.46" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(462.49677000660887 545.6645117013077) rotate(0 -1.190780973701635 -80.97310621170891)"><path d="M-0.62 -0.09 C-1.05 -26.87, -1.53 -134.53, -1.9 -161.39 M1.25 -1.18 C0.65 -28.26, -1.74 -136.22, -2.59 -163.22" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(460.1152080592056 380.14595635678495) rotate(0 105.3841161725918 -1.1907809737016066)"><path d="M0.98 -0.93 C36.1 -1.01, 176.54 -1, 211.51 -1.27 M0.04 1.2 C34.99 0.88, 175.96 -2.39, 210.95 -2.82" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(669.6926594306876 376.57361343568016) rotate(0 0.5953904868507607 82.75927767226133)"><path d="M-0.99 -0.41 C-0.54 27.2, 1.55 136.9, 1.72 164.64 M0.7 -1.68 C1.12 26.16, 0.78 138.12, 1.04 165.72" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(672.0742213780909 542.0921687802029) rotate(0 191.12034627910714 -2.976952434253974)"><path d="M0.95 0.4 C64.42 -0.86, 317.63 -5.42, 381.15 -6.62 M0 -0.44 C63.78 -1.63, 319.76 -4.51, 383.29 -5.43" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(672.1152080592055 548.1907594909206) rotate(0 0.5953904868508175 65.49295355358805)"><path d="M-0.92 1.14 C-0.95 23.33, -0.16 110.39, 0.31 131.92 M0.8 0.7 C1.09 22.66, 2.45 108.52, 2.56 130.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(672.1152080592055 548.1907594909206) rotate(0 0.5953904868508175 65.49295355358805)"><path d="M-6.25 106.9 C-1.55 113.53, 1.13 124.19, 2.56 130.29 M-6.25 106.9 C-4.64 113.13, -2.21 118.07, 2.56 130.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g><g transform="translate(672.1152080592055 548.1907594909206) rotate(0 0.5953904868508175 65.49295355358805)"><path d="M10.85 106.7 C9.68 113.27, 6.5 123.99, 2.56 130.29 M10.85 106.7 C8.22 113.14, 6.41 118.12, 2.56 130.29" stroke="#1e1e1e" stroke-width="2" fill="none"></path></g></g><mask></mask><g transform="translate(616.1485022952302 694.6568192562175) rotate(0 69.97916412353516 25)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">RBV Matched </text><text x="0" y="42.62" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Return here</text></g><g transform="translate(10 264.6402019077296) rotate(0 47.8125 12.500000000000014)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Set signal</text></g><g transform="translate(869.5323806105109 749.2654514964912) rotate(0 154.14583333333326 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">wait_for_set_completion= True</text></g><g transform="translate(521.8463297153439 749.5838303364346) rotate(0 160.32291666666663 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">wait_for_set_completion = False</text></g><g transform="translate(20.535767711378583 514.1120161220821) rotate(0 59.5625 12.5)"><text x="0" y="17.619999999999997" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="20px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">match signal</text></g><g transform="translate(957.8616550664754 651.6440183607504) rotate(0 7.677083492279053 22.5)"><text x="0" y="31.716" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">1</text></g><g transform="translate(691.1677036384312 638.6901134922423) rotate(0 12.583333015441895 22.5)"><text x="0" y="31.716" font-family="Excalifont, Xiaolai, Segoe UI Emoji" font-size="36px" fill="#e03131" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">2</text></g></svg>
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.8.0a4'
15
+ __version__ = version = '0.8.0a6'
16
16
  __version_tuple__ = version_tuple = (0, 8, 0)
@@ -61,6 +61,7 @@ from ._signal import (
61
61
  assert_emitted,
62
62
  assert_reading,
63
63
  assert_value,
64
+ observe_signals_value,
64
65
  observe_value,
65
66
  set_and_wait_for_other_value,
66
67
  set_and_wait_for_value,
@@ -158,6 +159,7 @@ __all__ = [
158
159
  "assert_reading",
159
160
  "assert_value",
160
161
  "observe_value",
162
+ "observe_signals_value",
161
163
  "set_and_wait_for_value",
162
164
  "set_and_wait_for_other_value",
163
165
  "soft_signal_r_and_setter",
@@ -37,8 +37,14 @@ class DeviceConnector:
37
37
 
38
38
  async def connect_mock(self, device: Device, mock: LazyMock):
39
39
  # Connect serially, no errors to gather up as in mock mode
40
+ exceptions: dict[str, Exception] = {}
40
41
  for name, child_device in device.children():
41
- await child_device.connect(mock=mock.child(name))
42
+ try:
43
+ await child_device.connect(mock=mock.child(name))
44
+ except Exception as e:
45
+ exceptions[name] = e
46
+ if exceptions:
47
+ raise NotConnected.with_other_exceptions_logged(exceptions)
42
48
 
43
49
  async def connect_real(self, device: Device, timeout: float, force_reconnect: bool):
44
50
  """Used during ``Device.connect``.
@@ -193,7 +199,8 @@ class DeviceVector(MutableMapping[int, DeviceT], Device):
193
199
  children: Mapping[int, DeviceT],
194
200
  name: str = "",
195
201
  ) -> None:
196
- self._children = dict(children)
202
+ self._children: dict[int, DeviceT] = {}
203
+ self.update(children)
197
204
  super().__init__(name=name)
198
205
 
199
206
  def __setattr__(self, name: str, child: Any) -> None:
@@ -28,7 +28,7 @@ from ._signal_backend import (
28
28
  SignalDatatypeV,
29
29
  )
30
30
  from ._soft_signal_backend import SoftSignalBackend
31
- from ._status import AsyncStatus
31
+ from ._status import AsyncStatus, completed_status
32
32
  from ._utils import (
33
33
  CALCULATE_TIMEOUT,
34
34
  DEFAULT_TIMEOUT,
@@ -448,7 +448,44 @@ async def observe_value(
448
448
  do_something_with(value)
449
449
  """
450
450
 
451
- q: asyncio.Queue[SignalDatatypeT | Status] = asyncio.Queue()
451
+ async for _, value in observe_signals_value(
452
+ signal, timeout=timeout, done_status=done_status
453
+ ):
454
+ yield value
455
+
456
+
457
+ async def observe_signals_value(
458
+ *signals: SignalR[SignalDatatypeT],
459
+ timeout: float | None = None,
460
+ done_status: Status | None = None,
461
+ ) -> AsyncGenerator[tuple[SignalR[SignalDatatypeT], SignalDatatypeT], None]:
462
+ """Subscribe to the value of a signal so it can be iterated from.
463
+
464
+ Parameters
465
+ ----------
466
+ signals:
467
+ Call subscribe_value on all the signals at the start, and clear_sub on it at the
468
+ end
469
+ timeout:
470
+ If given, how long to wait for each updated value in seconds. If an update
471
+ is not produced in this time then raise asyncio.TimeoutError
472
+ done_status:
473
+ If this status is complete, stop observing and make the iterator return.
474
+ If it raises an exception then this exception will be raised by the iterator.
475
+
476
+ Notes
477
+ -----
478
+ Example usage::
479
+
480
+ async for signal,value in observe_signals_values(sig1,sig2,..):
481
+ if signal is sig1:
482
+ do_something_with(value)
483
+ elif signal is sig2:
484
+ do_something_else_with(value)
485
+ """
486
+ q: asyncio.Queue[tuple[SignalR[SignalDatatypeT], SignalDatatypeT] | Status] = (
487
+ asyncio.Queue()
488
+ )
452
489
  if timeout is None:
453
490
  get_value = q.get
454
491
  else:
@@ -456,12 +493,23 @@ async def observe_value(
456
493
  async def get_value():
457
494
  return await asyncio.wait_for(q.get(), timeout)
458
495
 
496
+ cbs: dict[SignalR, Callback] = {}
497
+ for signal in signals:
498
+
499
+ def queue_value(value: SignalDatatypeT, signal=signal):
500
+ q.put_nowait((signal, value))
501
+
502
+ cbs[signal] = queue_value
503
+ signal.subscribe_value(queue_value)
504
+
459
505
  if done_status is not None:
460
506
  done_status.add_callback(q.put_nowait)
461
507
 
462
- signal.subscribe_value(q.put_nowait)
463
508
  try:
464
509
  while True:
510
+ # yield here in case something else is filling the queue
511
+ # like in test_observe_value_times_out_with_no_external_task()
512
+ await asyncio.sleep(0)
465
513
  item = await get_value()
466
514
  if done_status and item is done_status:
467
515
  if exc := done_status.exception():
@@ -469,9 +517,10 @@ async def observe_value(
469
517
  else:
470
518
  break
471
519
  else:
472
- yield cast(SignalDatatypeT, item)
520
+ yield cast(tuple[SignalR[SignalDatatypeT], SignalDatatypeT], item)
473
521
  finally:
474
- signal.clear_sub(q.put_nowait)
522
+ for signal, cb in cbs.items():
523
+ signal.clear_sub(cb)
475
524
 
476
525
 
477
526
  class _ValueChecker(Generic[SignalDatatypeT]):
@@ -536,15 +585,16 @@ async def wait_for_value(
536
585
  async def set_and_wait_for_other_value(
537
586
  set_signal: SignalW[SignalDatatypeT],
538
587
  set_value: SignalDatatypeT,
539
- read_signal: SignalR[SignalDatatypeV],
540
- read_value: SignalDatatypeV,
588
+ match_signal: SignalR[SignalDatatypeV],
589
+ match_value: SignalDatatypeV | Callable[[SignalDatatypeV], bool],
541
590
  timeout: float = DEFAULT_TIMEOUT,
542
591
  set_timeout: float | None = None,
592
+ wait_for_set_completion: bool = True,
543
593
  ) -> AsyncStatus:
544
594
  """Set a signal and monitor another signal until it has the specified value.
545
595
 
546
596
  This function sets a set_signal to a specified set_value and waits for
547
- a read_signal to have the read_value.
597
+ a match_signal to have the match_value.
548
598
 
549
599
  Parameters
550
600
  ----------
@@ -552,14 +602,16 @@ async def set_and_wait_for_other_value(
552
602
  The signal to set
553
603
  set_value:
554
604
  The value to set it to
555
- read_signal:
605
+ match_signal:
556
606
  The signal to monitor
557
- read_value:
607
+ match_value:
558
608
  The value to wait for
559
609
  timeout:
560
610
  How long to wait for the signal to have the value
561
611
  set_timeout:
562
612
  How long to wait for the set to complete
613
+ wait_for_set_completion:
614
+ This will wait for set completion #More info in how-to docs
563
615
 
564
616
  Notes
565
617
  -----
@@ -568,7 +620,7 @@ async def set_and_wait_for_other_value(
568
620
  set_and_wait_for_value(device.acquire, 1, device.acquire_rbv, 1)
569
621
  """
570
622
  # Start monitoring before the set to avoid a race condition
571
- values_gen = observe_value(read_signal)
623
+ values_gen = observe_value(match_signal)
572
624
 
573
625
  # Get the initial value from the monitor to make sure we've created it
574
626
  current_value = await anext(values_gen)
@@ -576,28 +628,33 @@ async def set_and_wait_for_other_value(
576
628
  status = set_signal.set(set_value, timeout=set_timeout)
577
629
 
578
630
  # If the value was the same as before no need to wait for it to change
579
- if current_value != read_value:
631
+ if current_value != match_value:
580
632
 
581
633
  async def _wait_for_value():
582
634
  async for value in values_gen:
583
- if value == read_value:
635
+ if value == match_value:
584
636
  break
585
637
 
586
638
  try:
587
639
  await asyncio.wait_for(_wait_for_value(), timeout)
640
+ if wait_for_set_completion:
641
+ await status
642
+ return status
588
643
  except asyncio.TimeoutError as e:
589
644
  raise TimeoutError(
590
- f"{read_signal.name} didn't match {read_value} in {timeout}s"
645
+ f"{match_signal.name} didn't match {match_value} in {timeout}s"
591
646
  ) from e
592
647
 
593
- return status
648
+ return completed_status()
594
649
 
595
650
 
596
651
  async def set_and_wait_for_value(
597
652
  signal: SignalRW[SignalDatatypeT],
598
653
  value: SignalDatatypeT,
654
+ match_value: SignalDatatypeT | Callable[[SignalDatatypeT], bool] | None = None,
599
655
  timeout: float = DEFAULT_TIMEOUT,
600
656
  status_timeout: float | None = None,
657
+ wait_for_set_completion: bool = True,
601
658
  ) -> AsyncStatus:
602
659
  """Set a signal and monitor it until it has that value.
603
660
 
@@ -612,10 +669,15 @@ async def set_and_wait_for_value(
612
669
  The signal to set
613
670
  value:
614
671
  The value to set it to
672
+ match_value:
673
+ The expected value of the signal after the operation.
674
+ Used to verify that the set operation was successful.
615
675
  timeout:
616
676
  How long to wait for the signal to have the value
617
677
  status_timeout:
618
678
  How long the returned Status will wait for the set to complete
679
+ wait_for_set_completion:
680
+ This will wait for set completion #More info in how-to docs
619
681
 
620
682
  Notes
621
683
  -----
@@ -623,6 +685,14 @@ async def set_and_wait_for_value(
623
685
 
624
686
  set_and_wait_for_value(device.acquire, 1)
625
687
  """
688
+ if match_value is None:
689
+ match_value = value
626
690
  return await set_and_wait_for_other_value(
627
- signal, value, signal, value, timeout, status_timeout
691
+ signal,
692
+ value,
693
+ signal,
694
+ match_value,
695
+ timeout,
696
+ status_timeout,
697
+ wait_for_set_completion,
628
698
  )
@@ -5,7 +5,7 @@ from abc import abstractmethod
5
5
  from collections.abc import Sequence
6
6
  from dataclasses import dataclass
7
7
  from functools import lru_cache
8
- from typing import Any, Generic, get_origin
8
+ from typing import Any, Generic, get_args, get_origin
9
9
 
10
10
  import numpy as np
11
11
  from bluesky.protocols import Reading
@@ -58,7 +58,7 @@ class SequenceEnumSoftConverter(SoftConverter[Sequence[EnumT]]):
58
58
 
59
59
  @dataclass
60
60
  class NDArraySoftConverter(SoftConverter[Array1D]):
61
- datatype: np.dtype
61
+ datatype: np.dtype | None = None
62
62
 
63
63
  def write_value(self, value: Any) -> Array1D:
64
64
  return np.array(() if value is None else value, dtype=self.datatype)
@@ -98,7 +98,11 @@ def make_converter(datatype: type[SignalDatatype]) -> SoftConverter:
98
98
  return SequenceStrSoftConverter()
99
99
  elif get_origin(datatype) == Sequence and enum_cls:
100
100
  return SequenceEnumSoftConverter(enum_cls)
101
+ elif datatype is np.ndarray:
102
+ return NDArraySoftConverter()
101
103
  elif get_origin(datatype) == np.ndarray:
104
+ if datatype not in get_args(SignalDatatype):
105
+ raise TypeError(f"Expected Array1D[dtype], got {datatype}")
102
106
  return NDArraySoftConverter(get_dtype(datatype))
103
107
  elif enum_cls:
104
108
  return EnumSoftConverter(enum_cls)
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Sequence
3
+ from collections.abc import Callable, Sequence
4
4
  from typing import Annotated, Any, TypeVar, get_origin
5
5
 
6
6
  import numpy as np
@@ -19,6 +19,13 @@ def _concat(value1, value2):
19
19
  return value1 + value2
20
20
 
21
21
 
22
+ def _make_default_factory(dtype: np.dtype) -> Callable[[], np.ndarray]:
23
+ def numpy_array_default_factory() -> np.ndarray:
24
+ return np.array([], dtype)
25
+
26
+ return numpy_array_default_factory
27
+
28
+
22
29
  class Table(BaseModel):
23
30
  """An abstraction of a Table of str to numpy array."""
24
31
 
@@ -45,9 +52,7 @@ class Table(BaseModel):
45
52
  NpArrayPydanticAnnotation.factory(
46
53
  data_type=dtype.type, dimensions=1, strict_data_typing=False
47
54
  ),
48
- Field(
49
- default_factory=lambda dtype=dtype: np.array([], dtype=dtype)
50
- ),
55
+ Field(default_factory=_make_default_factory(dtype)),
51
56
  ]
52
57
  elif get_origin(anno) is Sequence:
53
58
  new_anno = Annotated[anno, Field(default_factory=list)]
@@ -2,18 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import logging
5
- from collections.abc import Awaitable, Callable, Iterable, Sequence
5
+ from collections.abc import Awaitable, Callable, Iterable, Mapping, Sequence
6
6
  from dataclasses import dataclass
7
7
  from enum import Enum, EnumMeta
8
- from typing import (
9
- Any,
10
- Generic,
11
- Literal,
12
- ParamSpec,
13
- TypeVar,
14
- get_args,
15
- get_origin,
16
- )
8
+ from typing import Any, Generic, Literal, ParamSpec, TypeVar, get_args, get_origin
17
9
  from unittest.mock import Mock
18
10
 
19
11
  import numpy as np
@@ -22,7 +14,7 @@ T = TypeVar("T")
22
14
  P = ParamSpec("P")
23
15
  Callback = Callable[[T], None]
24
16
  DEFAULT_TIMEOUT = 10.0
25
- ErrorText = str | dict[str, Exception]
17
+ ErrorText = str | Mapping[str, Exception]
26
18
 
27
19
 
28
20
  class StrictEnum(str, Enum):
@@ -70,6 +62,13 @@ class NotConnected(Exception):
70
62
 
71
63
  self._errors = errors
72
64
 
65
+ @property
66
+ def sub_errors(self) -> Mapping[str, Exception]:
67
+ if isinstance(self._errors, dict):
68
+ return self._errors.copy()
69
+ else:
70
+ return {}
71
+
73
72
  def _format_sub_errors(self, name: str, error: Exception, indent="") -> str:
74
73
  if isinstance(error, NotConnected):
75
74
  error_txt = ":" + error.format_error_string(indent + self._indent_width)
@@ -100,6 +99,19 @@ class NotConnected(Exception):
100
99
  def __str__(self) -> str:
101
100
  return self.format_error_string(indent="")
102
101
 
102
+ @classmethod
103
+ def with_other_exceptions_logged(
104
+ cls, exceptions: Mapping[str, Exception]
105
+ ) -> NotConnected:
106
+ for name, exception in exceptions.items():
107
+ if not isinstance(exception, NotConnected):
108
+ logging.exception(
109
+ f"device `{name}` raised unexpected exception "
110
+ f"{type(exception).__name__}",
111
+ exc_info=exception,
112
+ )
113
+ return NotConnected(exceptions)
114
+
103
115
 
104
116
  @dataclass(frozen=True)
105
117
  class WatcherUpdate(Generic[T]):
@@ -137,14 +149,7 @@ async def wait_for_connection(**coros: Awaitable[None]):
137
149
  exceptions[name] = result
138
150
 
139
151
  if exceptions:
140
- for name, exception in exceptions.items():
141
- if not isinstance(exception, NotConnected):
142
- logging.exception(
143
- f"device `{name}` raised unexpected exception "
144
- f"{type(exception).__name__}",
145
- exc_info=exception,
146
- )
147
- raise NotConnected(exceptions)
152
+ raise NotConnected.with_other_exceptions_logged(exceptions)
148
153
 
149
154
 
150
155
  def get_dtype(datatype: type) -> np.dtype:
@@ -91,7 +91,9 @@ async def start_acquiring_driver_and_ensure_status(
91
91
  subsequent raising (if applicable) due to detector state.
92
92
  """
93
93
 
94
- status = await set_and_wait_for_value(driver.acquire, True, timeout=timeout)
94
+ status = await set_and_wait_for_value(
95
+ driver.acquire, True, timeout=timeout, wait_for_set_completion=False
96
+ )
95
97
 
96
98
  async def complete_acquisition() -> None:
97
99
  """NOTE: possible race condition here between the callback from
@@ -115,7 +115,7 @@ class CaLongStrConverter(CaConverter[str]):
115
115
  def __init__(self):
116
116
  super().__init__(str, dbr.DBR_CHAR_STR, dbr.DBR_CHAR_STR)
117
117
 
118
- def write_value_and_dbr(self, value: Any) -> Any:
118
+ def write_value(self, value: Any) -> Any:
119
119
  # Add a null in here as this is what the commandline caput does
120
120
  # TODO: this should be in the server so check if it can be pushed to asyn
121
121
  return value + "\0"
@@ -188,6 +188,7 @@ _datatype_converter_from_typeid: dict[
188
188
  ("epics:nt/NTScalarArray:1.0", "as"): (Sequence[str], PvaConverter),
189
189
  ("epics:nt/NTTable:1.0", "S"): (Table, PvaTableConverter),
190
190
  ("epics:nt/NTNDArray:1.0", "v"): (np.ndarray, PvaNDArrayConverter),
191
+ ("epics:nt/NTNDArray:1.0", "U"): (np.ndarray, PvaNDArrayConverter),
191
192
  }
192
193
 
193
194
 
@@ -55,7 +55,12 @@ class EigerController(DetectorController):
55
55
  async def arm(self):
56
56
  # TODO: Detector state should be an enum see https://github.com/DiamondLightSource/eiger-fastcs/issues/43
57
57
  self._arm_status = set_and_wait_for_other_value(
58
- self._drv.arm, 1, self._drv.state, "ready", timeout=DEFAULT_TIMEOUT
58
+ self._drv.arm,
59
+ 1,
60
+ self._drv.state,
61
+ "ready",
62
+ timeout=DEFAULT_TIMEOUT,
63
+ wait_for_set_completion=False,
59
64
  )
60
65
 
61
66
  async def wait_for_idle(self):
@@ -0,0 +1,24 @@
1
+ from ._example_ioc import (
2
+ CA_PVA_RECORDS,
3
+ PVA_RECORDS,
4
+ ExampleCaDevice,
5
+ ExampleEnum,
6
+ ExamplePvaDevice,
7
+ ExampleTable,
8
+ connect_example_device,
9
+ get_example_ioc,
10
+ )
11
+ from ._utils import TestingIOC, generate_random_PV_prefix
12
+
13
+ __all__ = [
14
+ "CA_PVA_RECORDS",
15
+ "PVA_RECORDS",
16
+ "ExampleCaDevice",
17
+ "ExampleEnum",
18
+ "ExamplePvaDevice",
19
+ "ExampleTable",
20
+ "connect_example_device",
21
+ "get_example_ioc",
22
+ "TestingIOC",
23
+ "generate_random_PV_prefix",
24
+ ]