ophyd-async 0.13.1__tar.gz → 0.13.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (323) hide show
  1. ophyd_async-0.13.3/.github/workflows/_system_test.yml +38 -0
  2. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/ci.yml +3 -1
  3. ophyd_async-0.13.3/.gitmodules +3 -0
  4. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/PKG-INFO +4 -2
  5. ophyd_async-0.13.3/docs/explanations/when-to-extend-movable.md +17 -0
  6. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/choose-right-baseclass.md +1 -1
  7. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/pyproject.toml +4 -2
  8. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/_version.py +3 -3
  9. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/__init__.py +2 -1
  10. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_signal.py +7 -0
  11. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_epics_connector.py +14 -1
  12. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/motor.py +30 -16
  13. {ophyd_async-0.13.1/src/ophyd_async/epics/eiger → ophyd_async-0.13.3/src/ophyd_async/epics/odin}/_odin_io.py +5 -3
  14. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/pmac/__init__.py +2 -0
  15. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/pmac/_pmac_io.py +2 -2
  16. ophyd_async-0.13.3/src/ophyd_async/epics/pmac/_pmac_trajectory.py +114 -0
  17. ophyd_async-0.13.3/src/ophyd_async/epics/pmac/_utils.py +847 -0
  18. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/eiger/_eiger.py +1 -1
  19. ophyd_async-0.13.3/src/ophyd_async/fastcs/jungfrau/__init__.py +29 -0
  20. ophyd_async-0.13.3/src/ophyd_async/fastcs/jungfrau/_controller.py +139 -0
  21. ophyd_async-0.13.3/src/ophyd_async/fastcs/jungfrau/_jungfrau.py +30 -0
  22. ophyd_async-0.13.3/src/ophyd_async/fastcs/jungfrau/_signals.py +94 -0
  23. ophyd_async-0.13.3/src/ophyd_async/fastcs/jungfrau/_utils.py +79 -0
  24. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_motor.py +11 -3
  25. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_point_detector.py +6 -3
  26. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_stage.py +14 -3
  27. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async.egg-info/PKG-INFO +4 -2
  28. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async.egg-info/SOURCES.txt +20 -2
  29. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async.egg-info/requires.txt +3 -1
  30. ophyd_async-0.13.3/system_tests/conftest.py +10 -0
  31. ophyd_async-0.13.3/system_tests/epics/adsim/baseline.yaml +32 -0
  32. ophyd_async-0.13.3/system_tests/epics/adsim/start_iocs.sh +14 -0
  33. ophyd_async-0.13.3/system_tests/epics/adsim/stop_iocs.sh +14 -0
  34. ophyd_async-0.13.3/system_tests/epics/adsim/test_adsim_system.py +237 -0
  35. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/system_tests/epics/eiger/test_eiger_system.py +5 -12
  36. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_auto_init_devices.py +2 -0
  37. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_signal.py +2 -2
  38. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/eiger/test_odin_io.py +2 -2
  39. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/pmac/test_pmac_io.py +2 -2
  40. ophyd_async-0.13.3/tests/epics/pmac/test_pmac_trajectory.py +170 -0
  41. ophyd_async-0.13.3/tests/epics/pmac/test_pmac_utils.py +922 -0
  42. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/signal/test_signals.py +33 -1
  43. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/test_motor.py +32 -0
  44. ophyd_async-0.13.3/tests/fastcs/jungfrau/test_controller.py +165 -0
  45. ophyd_async-0.13.3/tests/fastcs/jungfrau/test_utils.py +49 -0
  46. ophyd_async-0.13.3/tests/sim/__init__.py +0 -0
  47. ophyd_async-0.13.1/src/ophyd_async/epics/pmac/_utils.py +0 -231
  48. ophyd_async-0.13.1/tests/epics/pmac/test_pmac_utils.py +0 -324
  49. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.codecov.yml +0 -0
  50. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.copier-answers.yml +0 -0
  51. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.devcontainer/devcontainer.json +0 -0
  52. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.git-blame-ignore-revs +0 -0
  53. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/CONTRIBUTING.md +0 -0
  54. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  55. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  56. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  57. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/actions/install_requirements/action.yml +0 -0
  58. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/codeql/codeql-config.yml +0 -0
  59. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/dependabot.yml +0 -0
  60. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/pages/index.html +0 -0
  61. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/pages/make_switcher.py +0 -0
  62. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_codeql.yml +0 -0
  63. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_dist.yml +0 -0
  64. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_docs.yml +0 -0
  65. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_import_with_no_extras.yml +0 -0
  66. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_pypi.yml +0 -0
  67. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_release.yml +0 -0
  68. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_test.yml +0 -0
  69. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/_tox.yml +0 -0
  70. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.github/workflows/periodic.yml +0 -0
  71. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.gitignore +0 -0
  72. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/.pre-commit-config.yaml +0 -0
  73. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/Dockerfile +0 -0
  74. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/LICENSE +0 -0
  75. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/README.md +0 -0
  76. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/_static/custom.css +0 -0
  77. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/conf.py +0 -0
  78. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  79. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  80. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  81. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  82. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  83. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  84. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  85. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0008-signal-types.md +0 -0
  86. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  87. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  88. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/0011-buffer-updates-camonitor.md +0 -0
  89. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions/COPYME +0 -0
  90. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/decisions.md +0 -0
  91. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/declarative-vs-procedural.md +0 -0
  92. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/design-goals.md +0 -0
  93. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/device-connection-strategies.md +0 -0
  94. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/devices-signals-backends.md +0 -0
  95. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/fly-scanning.md +0 -0
  96. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/plan-stubs.md +0 -0
  97. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations/where-device-logic.md +0 -0
  98. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/explanations.md +0 -0
  99. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/genindex.rst +0 -0
  100. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/contribute.md +0 -0
  101. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/derive-one-signal-from-others.md +0 -0
  102. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/implement-ad-detector.md +0 -0
  103. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/interact-with-signals.md +0 -0
  104. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/put-device-back.md +0 -0
  105. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to/store-and-retrieve.md +0 -0
  106. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/how-to.md +0 -0
  107. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
  108. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/images/ophyd-async-logo.svg +0 -0
  109. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/images/ophyd-favicon.svg +0 -0
  110. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  111. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/index.md +0 -0
  112. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/reference.md +0 -0
  113. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials/implementing-detectors.md +0 -0
  114. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials/implementing-devices.md +0 -0
  115. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials/installation.md +0 -0
  116. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials/using-devices.md +0 -0
  117. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials/writing-tests-for-devices.md +0 -0
  118. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/docs/tutorials.md +0 -0
  119. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/setup.cfg +0 -0
  120. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/__init__.py +0 -0
  121. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/__main__.py +0 -0
  122. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/_docs_parser.py +0 -0
  123. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_derived_signal.py +0 -0
  124. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_derived_signal_backend.py +0 -0
  125. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_detector.py +0 -0
  126. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_device.py +0 -0
  127. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_device_filler.py +0 -0
  128. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_enums.py +0 -0
  129. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_flyer.py +0 -0
  130. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_hdf_dataset.py +0 -0
  131. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_log.py +0 -0
  132. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  133. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_protocol.py +0 -0
  134. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_providers.py +0 -0
  135. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_readable.py +0 -0
  136. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_settings.py +0 -0
  137. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_signal_backend.py +0 -0
  138. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  139. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_status.py +0 -0
  140. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_table.py +0 -0
  141. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_utils.py +0 -0
  142. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/core/_yaml_settings.py +0 -0
  143. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/__init__.py +0 -0
  144. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adandor/__init__.py +0 -0
  145. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  146. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
  147. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
  148. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  149. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  150. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
  151. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  152. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  153. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  154. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  155. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_core_logic.py +0 -0
  156. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
  157. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
  158. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
  159. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  160. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
  161. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  162. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  163. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  164. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  165. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  166. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  167. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  168. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  169. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  170. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  171. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  172. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  173. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  174. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  175. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  176. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
  177. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  178. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/__init__.py +0 -0
  179. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_aioca.py +0 -0
  180. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  181. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_p4p.py +0 -0
  182. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  183. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_signal.py +0 -0
  184. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/core/_util.py +0 -0
  185. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/__init__.py +0 -0
  186. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/__main__.py +0 -0
  187. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  188. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/_motor.py +0 -0
  189. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  190. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  191. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/_stage.py +0 -0
  192. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/motor.db +0 -0
  193. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  194. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  195. {ophyd_async-0.13.1/src/ophyd_async/epics/eiger → ophyd_async-0.13.3/src/ophyd_async/epics/odin}/__init__.py +0 -0
  196. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/signal.py +0 -0
  197. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/testing/__init__.py +0 -0
  198. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
  199. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/testing/_utils.py +0 -0
  200. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/testing/test_records.db +0 -0
  201. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  202. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/__init__.py +0 -0
  203. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/core.py +0 -0
  204. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
  205. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
  206. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/eiger/_eiger_io.py +0 -0
  207. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  208. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  209. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_block.py +0 -0
  210. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  211. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  212. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  213. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
  214. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
  215. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  216. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  217. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  218. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  219. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  220. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  221. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  222. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  223. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/py.typed +0 -0
  224. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/__init__.py +0 -0
  225. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/__main__.py +0 -0
  226. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_blob_detector.py +0 -0
  227. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
  228. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
  229. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
  230. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
  231. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/sim/_pattern_generator.py +0 -0
  232. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/__init__.py +0 -0
  233. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/__init__.py +0 -0
  234. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_base_device.py +0 -0
  235. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_converters.py +0 -0
  236. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_signal.py +0 -0
  237. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
  238. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
  239. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/core/_utils.py +0 -0
  240. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/__init__.py +0 -0
  241. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/_counter.py +0 -0
  242. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/_detector.py +0 -0
  243. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/_mover.py +0 -0
  244. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  245. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  246. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/testing/__init__.py +0 -0
  247. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  248. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/__init__.py +0 -0
  249. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  250. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_assert.py +0 -0
  251. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
  252. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  253. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_single_derived.py +0 -0
  254. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_utils.py +0 -0
  255. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  256. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  257. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/src/ophyd_async.egg-info/top_level.txt +0 -0
  258. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/system_tests/epics/eiger/README.md +0 -0
  259. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  260. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/conftest.py +0 -0
  261. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_detector.py +0 -0
  262. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_device.py +0 -0
  263. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_flyer.py +0 -0
  264. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_log.py +0 -0
  265. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_mock_signal_backend.py +0 -0
  266. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_multi_derived_signal.py +0 -0
  267. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_observe.py +0 -0
  268. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_protocol.py +0 -0
  269. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_providers.py +0 -0
  270. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_readable.py +0 -0
  271. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_single_derived_signal.py +0 -0
  272. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_soft_signal_backend.py +0 -0
  273. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_status.py +0 -0
  274. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_subset_enum.py +0 -0
  275. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_table.py +0 -0
  276. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_utils.py +0 -0
  277. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/core/test_watchable_async_status.py +0 -0
  278. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adandor/test_andor.py +0 -0
  279. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adaravis/test_aravis.py +0 -0
  280. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_cont_acq_detector.py +0 -0
  281. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_detectors.py +0 -0
  282. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_drivers.py +0 -0
  283. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_plugins.py +0 -0
  284. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_scans.py +0 -0
  285. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_single_trigger.py +0 -0
  286. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adcore/test_writers.py +0 -0
  287. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adkinetix/test_kinetix.py +0 -0
  288. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adpilatus/test_pilatus.py +0 -0
  289. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/adsimdetector/test_sim.py +0 -0
  290. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/advimba/test_vimba.py +0 -0
  291. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/conftest.py +0 -0
  292. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/demo/test_epics_demo.py +0 -0
  293. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/pvi/test_pvi.py +0 -0
  294. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/signal/test_common.py +0 -0
  295. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/signal/test_yaml_save_ca.yaml +0 -0
  296. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/signal/test_yaml_save_pva.yaml +0 -0
  297. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/epics/test_areadetector_subclass_naming.py +0 -0
  298. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/eiger/test_eiger_controller.py +0 -0
  299. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/eiger/test_eiger_detector.py +0 -0
  300. {ophyd_async-0.13.1/tests/sim → ophyd_async-0.13.3/tests/fastcs/jungfrau}/__init__.py +0 -0
  301. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/db/panda.db +0 -0
  302. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_hdf_panda.py +0 -0
  303. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_panda_connect.py +0 -0
  304. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_panda_control.py +0 -0
  305. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_panda_utils.py +0 -0
  306. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_seq_table.py +0 -0
  307. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_trigger.py +0 -0
  308. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/fastcs/panda/test_writer.py +0 -0
  309. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/plan_stubs/test_ensure_connected.py +0 -0
  310. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/plan_stubs/test_fly.py +0 -0
  311. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/plan_stubs/test_settings.py +0 -0
  312. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/plan_stubs/test_setup.py +0 -0
  313. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/sim/test_sim_blob_detector.py +0 -0
  314. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/sim/test_sim_motor.py +0 -0
  315. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/tango/conftest.py +0 -0
  316. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/tango/context_subprocess.py +0 -0
  317. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/tango/test_base_device.py +0 -0
  318. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/tango/test_tango_signals.py +0 -0
  319. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/tango/test_tango_transport.py +0 -0
  320. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/test_cli.py +0 -0
  321. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/test_data/test_yaml_config_save.yaml +0 -0
  322. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/test_data/test_yaml_save.yaml +0 -0
  323. {ophyd_async-0.13.1 → ophyd_async-0.13.3}/tests/test_tutorials.py +0 -0
@@ -0,0 +1,38 @@
1
+ on:
2
+ workflow_call:
3
+
4
+ env:
5
+ # https://github.com/pytest-dev/pytest/issues/2042
6
+ PY_IGNORE_IMPORTMISMATCH: "1"
7
+
8
+ jobs:
9
+ run:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v4
15
+ with:
16
+ # Need this to get version number from last tag
17
+ fetch-depth: 0
18
+
19
+ - name: Install dev versions of python packages
20
+ uses: ./.github/actions/install_requirements
21
+
22
+ - name: Checkout simulated devices
23
+ uses: actions/checkout@v4
24
+ with:
25
+ repository: epics-containers/example-services
26
+ path: example-services
27
+ ref: 'main'
28
+
29
+ - name: Run docker compose
30
+ uses: hoverkraft-tech/compose-action@v2.3.0
31
+ with:
32
+ compose-file: "./example-services/compose.yaml"
33
+ services: |
34
+ bl01t-di-cam-01
35
+ ca-gateway
36
+
37
+ - name: Run system tests
38
+ run: pytest system_tests/epics/adsim
@@ -38,6 +38,8 @@ jobs:
38
38
  docs:
39
39
  uses: ./.github/workflows/_docs.yml
40
40
 
41
+ system_tests:
42
+ uses: ./.github/workflows/_system_test.yml
41
43
 
42
44
  dist:
43
45
  uses: ./.github/workflows/_dist.yml
@@ -53,7 +55,7 @@ jobs:
53
55
  uses: ./.github/workflows/_codeql.yml
54
56
 
55
57
  release:
56
- needs: [dist, test, docs]
58
+ needs: [dist, test, docs, system_tests]
57
59
  if: github.ref_type == 'tag'
58
60
  uses: ./.github/workflows/_release.yml
59
61
  permissions:
@@ -0,0 +1,3 @@
1
+ [submodule "example-services"]
2
+ path = example-services
3
+ url = https://github.com/epics-containers/example-services.git
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.13.1
3
+ Version: 0.13.3
4
4
  Summary: Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
5
5
  Author-email: Tom Cobb <tom.cobb@diamond.ac.uk>
6
6
  License: BSD 3-Clause License
@@ -49,7 +49,8 @@ Requires-Dist: colorlog
49
49
  Requires-Dist: pydantic>=2.0
50
50
  Requires-Dist: pydantic-numpy
51
51
  Requires-Dist: stamina>=23.1.0
52
- Requires-Dist: scanspec>=1.0a1
52
+ Requires-Dist: scanspec>=0.8
53
+ Requires-Dist: velocity-profile
53
54
  Provides-Extra: sim
54
55
  Requires-Dist: h5py; extra == "sim"
55
56
  Provides-Extra: ca
@@ -87,6 +88,7 @@ Requires-Dist: pytest-forked; extra == "dev"
87
88
  Requires-Dist: pytest-rerunfailures; extra == "dev"
88
89
  Requires-Dist: pytest-timeout; extra == "dev"
89
90
  Requires-Dist: ruff; extra == "dev"
91
+ Requires-Dist: scanspec>=1.0a1; extra == "dev"
90
92
  Requires-Dist: sphinx-autobuild; extra == "dev"
91
93
  Requires-Dist: sphinx-autodoc2; extra == "dev"
92
94
  Requires-Dist: sphinxcontrib-mermaid; extra == "dev"
@@ -0,0 +1,17 @@
1
+ # When should a device extend movable
2
+
3
+ The [`Movable`](#bluesky.protocols.Movable) protocol indicates that a device has a `set` method which can be called in the bluesky through the plan stubs [`bps.abs_set`](#bluesky.plan_stubs.abs_set) and [`bps.mv`](#bluesky.plan_stubs.mv). The [RunEngine](#bluesky.run_engine.RunEngine) treats this `set` as an atomic operation. A `Movable` device is appropriate when:
4
+
5
+ - The `set` involves changing multiple signals in parallel alongside a desired ordering of the setting of signals - having this logic inside an asyncio function can provide speedup.
6
+
7
+ - The `RunEngine` should not be altering any other devices while this `set` is taking place.
8
+
9
+ - There is only one clear interpretation of what it means to set the device. For example, setting a motor is fairly unambiguous whereas setting a detector could mean a number of different things.
10
+
11
+ - You are doing some logic that a user will almost always want to do with this device.
12
+
13
+ The `set` method, in general, should be used be used with primitive values rather than more complex types, for example, dataclasses. Using the latter here leads to extra boilerplate at the plan level. An exception to this is where using `set` will provide speedup - in this case it could be worth the extra boilerplate.
14
+
15
+ ## What to use instead
16
+
17
+ If the device doesn't satisfy the above criteria, it is generally more suitable to be using combinations of [`bps.mv`](#bluesky.plan_stubs.mv) and [`bps.abs_set`](#bluesky.plan_stubs.abs_set) on individual signals of a plan's devices. This avoids adding unnecessary complexity to the device whilst giving the plan more flexability.
@@ -18,7 +18,7 @@ There are some utility baseclasses that allow you to create a Device pre-populat
18
18
 
19
19
  There are some [bluesky protocols](inv:bluesky#hardware) that show the verbs you can implement to add functionality in standard plans. For example:
20
20
 
21
- - [](#bluesky.protocols.Movable) to add behavior during `bps.mv` and `bps.abs_set`
21
+ - [](#bluesky.protocols.Movable) to add behavior during `bps.mv` and `bps.abs_set`. See [here](../explanations/when-to-extend-movable.md) for deciding if a device should extend movable.
22
22
  - [](#bluesky.protocols.Triggerable) to add behavior before `read()` in `bps.scan`
23
23
 
24
24
  It is not strictly required to add the protocol class as a baseclass (the presence of a method with the right signature is all that is required) but generally this is done so that the IDE gives you help when filling in the method, and the type checker knows to check that you have filled it in correctly.
@@ -21,7 +21,8 @@ dependencies = [
21
21
  "pydantic>=2.0",
22
22
  "pydantic-numpy",
23
23
  "stamina>=23.1.0",
24
- "scanspec>=1.0a1",
24
+ "scanspec>=0.8",
25
+ "velocity-profile",
25
26
  ]
26
27
  dynamic = ["version"]
27
28
  license.file = "LICENSE"
@@ -59,6 +60,7 @@ dev = [
59
60
  "pytest-rerunfailures",
60
61
  "pytest-timeout",
61
62
  "ruff",
63
+ "scanspec>=1.0a1",
62
64
  "sphinx-autobuild",
63
65
  "sphinx-autodoc2",
64
66
  "sphinxcontrib-mermaid",
@@ -103,7 +105,7 @@ markers = [
103
105
  ]
104
106
  asyncio_mode = "auto"
105
107
  asyncio_default_fixture_loop_scope = "function"
106
- timeout = 0.75
108
+ timeout = 1
107
109
  [tool.coverage.run]
108
110
  data_file = "/tmp/ophyd_async.coverage"
109
111
 
@@ -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.13.1'
32
- __version_tuple__ = version_tuple = (0, 13, 1)
31
+ __version__ = version = '0.13.3'
32
+ __version_tuple__ = version_tuple = (0, 13, 3)
33
33
 
34
- __commit_id__ = commit_id = 'g228f25c8b'
34
+ __commit_id__ = commit_id = 'gabcdf5983'
@@ -6,7 +6,7 @@ from ._derived_signal import (
6
6
  derived_signal_rw,
7
7
  derived_signal_w,
8
8
  )
9
- from ._derived_signal_backend import Transform
9
+ from ._derived_signal_backend import Transform, merge_gathered_dicts
10
10
  from ._detector import (
11
11
  DetectorController,
12
12
  DetectorTrigger,
@@ -212,6 +212,7 @@ __all__ = [
212
212
  "derived_signal_w",
213
213
  "Transform",
214
214
  "DerivedSignalFactory",
215
+ "merge_gathered_dicts",
215
216
  # Back compat - delete before 1.0
216
217
  "ConfigSignal",
217
218
  "HintedSignal",
@@ -121,6 +121,13 @@ class _SignalCache(Generic[SignalDatatypeT]):
121
121
  self._valid = asyncio.Event()
122
122
  self._reading: Reading[SignalDatatypeT] | None = None
123
123
  self.backend: SignalBackend[SignalDatatypeT] = backend
124
+ try:
125
+ asyncio.get_running_loop()
126
+ except RuntimeError as e:
127
+ raise RuntimeError(
128
+ "Need a running event loop to subscribe to a signal, "
129
+ "are you trying to run subscribe outside a plan?"
130
+ ) from e
124
131
  signal.log.debug(f"Making subscription on source {signal.source}")
125
132
  backend.set_callback(self._callback)
126
133
 
@@ -10,7 +10,20 @@ from ._signal import EpicsSignalBackend, get_signal_backend_type, split_protocol
10
10
 
11
11
  @dataclass
12
12
  class PvSuffix:
13
- """Define the PV suffix to be appended to the device prefix."""
13
+ """Define the PV suffix to be appended to the device prefix.
14
+
15
+ For a SignalRW:
16
+ - If you use the same "Suffix" for the read and write PV then use PvSuffix("Suffix")
17
+ - If you have "Suffix" for the write PV and "Suffix_RBV" for the read PV then use
18
+ PvSuffix.rbv("Suffix")
19
+ - If you have "WriteSuffix" for the write PV and "ReadSuffix" for the read PV then
20
+ you use PvSuffix(read_suffix="ReadSuffix", write_suffix="WriteSuffix")
21
+
22
+ For a SignalR:
23
+ - If you have "Suffix" for the read PV then use PvSuffix("Suffix")
24
+ - If you have "Suffix_RBV" for the read PV then use PvSuffix("Suffix_RBV"), do not
25
+ use PvSuffix.rbv as that will try to connect to multiple PVs
26
+ """
14
27
 
15
28
  read_suffix: str
16
29
  write_suffix: str | None = None
@@ -106,6 +106,33 @@ class Motor(
106
106
  # Readback should be named the same as its parent in read()
107
107
  self.user_readback.set_name(name)
108
108
 
109
+ async def check_motor_limit(self, abs_start_pos: float, abs_end_pos: float):
110
+ """Check the positions are within limits.
111
+
112
+ Will raise a MotorLimitsException if the given absolute positions will be
113
+ outside the motor soft limits.
114
+ """
115
+ motor_lower_limit, motor_upper_limit, egu = await asyncio.gather(
116
+ self.low_limit_travel.get_value(),
117
+ self.high_limit_travel.get_value(),
118
+ self.motor_egu.get_value(),
119
+ )
120
+
121
+ # EPICS motor record treats limits of 0, 0 as no limit
122
+ if motor_lower_limit == 0 and motor_upper_limit == 0:
123
+ return
124
+
125
+ if (
126
+ not motor_upper_limit >= abs_start_pos >= motor_lower_limit
127
+ or not motor_upper_limit >= abs_end_pos >= motor_lower_limit
128
+ ):
129
+ raise MotorLimitsException(
130
+ f"{self.name} motor trajectory for requested fly/move is from "
131
+ f"{abs_start_pos}{egu} to "
132
+ f"{abs_end_pos}{egu} but motor limits are "
133
+ f"{motor_lower_limit}{egu} <= x <= {motor_upper_limit}{egu} "
134
+ )
135
+
109
136
  @AsyncStatus.wrap
110
137
  async def prepare(self, value: FlyMotorInfo):
111
138
  """Move to the beginning of a suitable run-up distance ready for a fly scan."""
@@ -126,22 +153,7 @@ class Motor(
126
153
  ramp_up_start_pos = value.ramp_up_start_pos(acceleration_time)
127
154
  ramp_down_end_pos = value.ramp_down_end_pos(acceleration_time)
128
155
 
129
- motor_lower_limit, motor_upper_limit, egu = await asyncio.gather(
130
- self.low_limit_travel.get_value(),
131
- self.high_limit_travel.get_value(),
132
- self.motor_egu.get_value(),
133
- )
134
-
135
- if (
136
- not motor_upper_limit >= ramp_up_start_pos >= motor_lower_limit
137
- or not motor_upper_limit >= ramp_down_end_pos >= motor_lower_limit
138
- ):
139
- raise MotorLimitsException(
140
- f"Motor trajectory for requested fly is from "
141
- f"{ramp_up_start_pos}{egu} to "
142
- f"{ramp_down_end_pos}{egu} but motor limits are "
143
- f"{motor_lower_limit}{egu} <= x <= {motor_upper_limit}{egu} "
144
- )
156
+ await self.check_motor_limit(ramp_up_start_pos, ramp_down_end_pos)
145
157
 
146
158
  # move to prepare position at maximum velocity
147
159
  await self.velocity.set(abs(max_speed))
@@ -199,6 +211,8 @@ class Motor(
199
211
  msg = "Mover has zero velocity"
200
212
  raise ValueError(msg) from error
201
213
 
214
+ await self.check_motor_limit(old_position, new_position)
215
+
202
216
  move_status = self.user_setpoint.set(new_position, wait=True, timeout=timeout)
203
217
  async for current_position in observe_value(
204
218
  self.user_readback, done_status=move_status
@@ -90,11 +90,11 @@ class OdinWriter(DetectorWriter):
90
90
  self,
91
91
  path_provider: PathProvider,
92
92
  odin_driver: Odin,
93
- eiger_bit_depth: SignalR[int],
93
+ detector_bit_depth: SignalR[int],
94
94
  ) -> None:
95
95
  self._drv = odin_driver
96
96
  self._path_provider = path_provider
97
- self._eiger_bit_depth = Reference(eiger_bit_depth)
97
+ self._detector_bit_depth = Reference(detector_bit_depth)
98
98
  self._capture_status: AsyncStatus | None = None
99
99
  super().__init__()
100
100
 
@@ -103,7 +103,9 @@ class OdinWriter(DetectorWriter):
103
103
  self._exposures_per_event = exposures_per_event
104
104
 
105
105
  await asyncio.gather(
106
- self._drv.data_type.set(f"UInt{await self._eiger_bit_depth().get_value()}"),
106
+ self._drv.data_type.set(
107
+ f"UInt{await self._detector_bit_depth().get_value()}"
108
+ ),
107
109
  self._drv.num_to_capture.set(0),
108
110
  self._drv.file_path.set(str(info.directory_path)),
109
111
  self._drv.file_name.set(info.filename),
@@ -1,8 +1,10 @@
1
1
  from ._pmac_io import PmacAxisAssignmentIO, PmacCoordIO, PmacIO, PmacTrajectoryIO
2
+ from ._pmac_trajectory import PmacTrajectoryTriggerLogic
2
3
 
3
4
  __all__ = [
4
5
  "PmacAxisAssignmentIO",
5
6
  "PmacCoordIO",
6
7
  "PmacIO",
7
8
  "PmacTrajectoryIO",
9
+ "PmacTrajectoryTriggerLogic",
8
10
  ]
@@ -72,7 +72,7 @@ class PmacCoordIO(Device):
72
72
  self.cs_port = epics_signal_r(str, f"{prefix}Port")
73
73
  self.cs_axis_setpoint = DeviceVector(
74
74
  {
75
- i + 1: epics_signal_rw(np.float64, f"{prefix}M{i + 1}:DirectDemand")
75
+ i + 1: epics_signal_rw(float, f"{prefix}M{i + 1}:DirectDemand")
76
76
  for i in range(len(CS_LETTERS))
77
77
  }
78
78
  )
@@ -93,7 +93,7 @@ class PmacIO(Device):
93
93
 
94
94
  self.assignment = DeviceVector(
95
95
  {
96
- i: PmacAxisAssignmentIO(motor_prefix)
96
+ i: PmacAxisAssignmentIO(motor_prefix + ":")
97
97
  for i, motor_prefix in enumerate(motor_prefixes)
98
98
  }
99
99
  )
@@ -0,0 +1,114 @@
1
+ import asyncio
2
+
3
+ import numpy as np
4
+ from scanspec.core import Path
5
+ from scanspec.specs import Spec
6
+
7
+ from ophyd_async.core import (
8
+ DEFAULT_TIMEOUT,
9
+ FlyerController,
10
+ set_and_wait_for_value,
11
+ wait_for_value,
12
+ )
13
+ from ophyd_async.epics.motor import Motor
14
+ from ophyd_async.epics.pmac import PmacIO
15
+ from ophyd_async.epics.pmac._pmac_io import CS_LETTERS
16
+ from ophyd_async.epics.pmac._utils import (
17
+ _PmacMotorInfo,
18
+ _Trajectory,
19
+ calculate_ramp_position_and_duration,
20
+ )
21
+
22
+
23
+ class PmacTrajectoryTriggerLogic(FlyerController):
24
+ def __init__(self, pmac: PmacIO) -> None:
25
+ self.pmac = pmac
26
+ self.scantime: float | None = None
27
+
28
+ async def prepare(self, value: Spec[Motor]):
29
+ slice = Path(value.calculate()).consume()
30
+ motor_info = await _PmacMotorInfo.from_motors(self.pmac, slice.axes())
31
+ ramp_up_pos, ramp_up_time = calculate_ramp_position_and_duration(
32
+ slice, motor_info, True
33
+ )
34
+ ramp_down_pos, ramp_down_time = calculate_ramp_position_and_duration(
35
+ slice, motor_info, False
36
+ )
37
+ trajectory = _Trajectory.from_slice(slice, ramp_up_time, motor_info)
38
+ await asyncio.gather(
39
+ self._build_trajectory(
40
+ trajectory, motor_info, ramp_down_pos, ramp_down_time
41
+ ),
42
+ self._move_to_start(motor_info, ramp_up_pos),
43
+ )
44
+
45
+ async def kickoff(self):
46
+ if not self.scantime:
47
+ raise RuntimeError("Cannot kickoff. Must call prepare first.")
48
+ self.status = await self.pmac.trajectory.execute_profile.set(
49
+ True, timeout=self.scantime + 1
50
+ )
51
+
52
+ async def complete(self):
53
+ if not self.scantime:
54
+ raise RuntimeError("Cannot complete. Must call prepare first.")
55
+ await wait_for_value(
56
+ self.pmac.trajectory.execute_profile,
57
+ False,
58
+ timeout=self.scantime + DEFAULT_TIMEOUT,
59
+ )
60
+
61
+ async def stop(self):
62
+ await self.pmac.trajectory.abort_profile.set(True)
63
+
64
+ async def _build_trajectory(
65
+ self,
66
+ trajectory: _Trajectory,
67
+ motor_info: _PmacMotorInfo,
68
+ ramp_down_pos: dict[Motor, np.float64],
69
+ ramp_down_time: float,
70
+ ):
71
+ trajectory = trajectory.append_ramp_down(ramp_down_pos, ramp_down_time, 0)
72
+ self.scantime = np.sum(trajectory.durations)
73
+ use_axis = {axis + 1: False for axis in range(len(CS_LETTERS))}
74
+
75
+ for motor, number in motor_info.motor_cs_index.items():
76
+ use_axis[number + 1] = True
77
+ await self.pmac.trajectory.positions[number + 1].set(
78
+ trajectory.positions[motor]
79
+ )
80
+ await self.pmac.trajectory.velocities[number + 1].set(
81
+ trajectory.velocities[motor]
82
+ )
83
+
84
+ coros = [
85
+ self.pmac.trajectory.profile_cs_name.set(motor_info.cs_port),
86
+ self.pmac.trajectory.time_array.set(trajectory.durations),
87
+ self.pmac.trajectory.user_array.set(trajectory.user_programs),
88
+ self.pmac.trajectory.points_to_build.set(len(trajectory.durations)),
89
+ self.pmac.trajectory.calculate_velocities.set(False),
90
+ ] + [
91
+ self.pmac.trajectory.use_axis[number].set(use)
92
+ for number, use in use_axis.items()
93
+ ]
94
+ await asyncio.gather(*coros)
95
+ await self.pmac.trajectory.build_profile.set(True)
96
+
97
+ async def _move_to_start(
98
+ self, motor_info: _PmacMotorInfo, ramp_up_position: dict[Motor, np.float64]
99
+ ):
100
+ coord = self.pmac.coord[motor_info.cs_number]
101
+ coros = []
102
+ await coord.defer_moves.set(True)
103
+ for motor, position in ramp_up_position.items():
104
+ coros.append(
105
+ set_and_wait_for_value(
106
+ coord.cs_axis_setpoint[motor_info.motor_cs_index[motor] + 1],
107
+ position,
108
+ set_timeout=10,
109
+ wait_for_set_completion=False,
110
+ )
111
+ )
112
+ statuses = await asyncio.gather(*coros)
113
+ await coord.defer_moves.set(False)
114
+ await asyncio.gather(*statuses)