ophyd-async 0.10.1__tar.gz → 0.11__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 (300) hide show
  1. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_test.yml +13 -3
  2. {ophyd_async-0.10.1 → ophyd_async-0.11}/PKG-INFO +2 -2
  3. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/devices-signals-backends.md +1 -1
  4. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/derive-one-signal-from-others.md +2 -2
  5. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials/implementing-detectors.md +1 -1
  6. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials/implementing-devices.md +1 -0
  7. {ophyd_async-0.10.1 → ophyd_async-0.11}/pyproject.toml +2 -2
  8. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/_version.py +2 -2
  9. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/__init__.py +12 -1
  10. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_derived_signal.py +68 -22
  11. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_derived_signal_backend.py +46 -24
  12. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_detector.py +3 -3
  13. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_device.py +24 -16
  14. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_flyer.py +35 -1
  15. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_hdf_dataset.py +11 -10
  16. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_signal.py +43 -28
  17. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_table.py +3 -3
  18. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_utils.py +25 -0
  19. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_yaml_settings.py +3 -3
  20. ophyd_async-0.11/src/ophyd_async/epics/adandor/__init__.py +15 -0
  21. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adandor/_andor_controller.py +5 -8
  22. ophyd_async-0.11/src/ophyd_async/epics/adandor/_andor_io.py +27 -0
  23. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_hdf_writer.py +12 -19
  24. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/eiger/_odin_io.py +4 -2
  25. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/motor.py +46 -96
  26. ophyd_async-0.11/src/ophyd_async/epics/pmac/__init__.py +3 -0
  27. ophyd_async-0.11/src/ophyd_async/epics/pmac/_pmac_io.py +100 -0
  28. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/eiger/__init__.py +1 -2
  29. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/eiger/_eiger.py +3 -9
  30. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_trigger.py +4 -4
  31. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_writer.py +15 -13
  32. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/__init__.py +1 -2
  33. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_blob_detector_writer.py +6 -12
  34. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_mirror_horizontal.py +3 -2
  35. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_mirror_vertical.py +1 -0
  36. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_motor.py +13 -43
  37. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async.egg-info/PKG-INFO +2 -2
  38. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async.egg-info/SOURCES.txt +3 -0
  39. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async.egg-info/requires.txt +1 -1
  40. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_device.py +1 -1
  41. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_flyer.py +1 -0
  42. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_multi_derived_signal.py +1 -1
  43. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_observe.py +1 -0
  44. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_signal.py +51 -2
  45. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_single_derived_signal.py +29 -6
  46. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_soft_signal_backend.py +30 -1
  47. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_cont_acq_detector.py +2 -4
  48. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_drivers.py +1 -0
  49. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_scans.py +1 -0
  50. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adsimdetector/test_sim.py +4 -0
  51. ophyd_async-0.11/tests/epics/pmac/test_pmac_io.py +91 -0
  52. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/signal/test_signals.py +18 -0
  53. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/test_motor.py +32 -30
  54. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/eiger/test_eiger_controller.py +24 -2
  55. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/eiger/test_eiger_detector.py +4 -21
  56. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_panda_connect.py +4 -0
  57. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/sim/test_sim_motor.py +4 -2
  58. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/tango/test_base_device.py +5 -0
  59. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/tango/test_tango_signals.py +2 -0
  60. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/tango/test_tango_transport.py +6 -0
  61. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/test_tutorials.py +1 -0
  62. ophyd_async-0.10.1/src/ophyd_async/epics/adandor/__init__.py +0 -9
  63. ophyd_async-0.10.1/src/ophyd_async/epics/adandor/_andor_io.py +0 -34
  64. {ophyd_async-0.10.1 → ophyd_async-0.11}/.codecov.yml +0 -0
  65. {ophyd_async-0.10.1 → ophyd_async-0.11}/.copier-answers.yml +0 -0
  66. {ophyd_async-0.10.1 → ophyd_async-0.11}/.devcontainer/devcontainer.json +0 -0
  67. {ophyd_async-0.10.1 → ophyd_async-0.11}/.git-blame-ignore-revs +0 -0
  68. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/CONTRIBUTING.md +0 -0
  69. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  70. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  71. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  72. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/actions/install_requirements/action.yml +0 -0
  73. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/codeql/codeql-config.yml +0 -0
  74. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/dependabot.yml +0 -0
  75. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/pages/index.html +0 -0
  76. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/pages/make_switcher.py +0 -0
  77. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_check.yml +0 -0
  78. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_codeql.yml +0 -0
  79. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_dist.yml +0 -0
  80. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_docs.yml +0 -0
  81. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_import_with_no_extras.yml +0 -0
  82. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_pypi.yml +0 -0
  83. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_release.yml +0 -0
  84. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/_tox.yml +0 -0
  85. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/ci.yml +0 -0
  86. {ophyd_async-0.10.1 → ophyd_async-0.11}/.github/workflows/periodic.yml +0 -0
  87. {ophyd_async-0.10.1 → ophyd_async-0.11}/.gitignore +0 -0
  88. {ophyd_async-0.10.1 → ophyd_async-0.11}/.pre-commit-config.yaml +0 -0
  89. {ophyd_async-0.10.1 → ophyd_async-0.11}/Dockerfile +0 -0
  90. {ophyd_async-0.10.1 → ophyd_async-0.11}/LICENSE +0 -0
  91. {ophyd_async-0.10.1 → ophyd_async-0.11}/README.md +0 -0
  92. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/_static/custom.css +0 -0
  93. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/conf.py +0 -0
  94. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  95. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  96. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  97. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  98. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  99. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  100. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  101. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0008-signal-types.md +0 -0
  102. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  103. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  104. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions/COPYME +0 -0
  105. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/decisions.md +0 -0
  106. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/declarative-vs-procedural.md +0 -0
  107. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/design-goals.md +0 -0
  108. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/device-connection-strategies.md +0 -0
  109. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/flyscanning.md +0 -0
  110. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations/where-device-logic.md +0 -0
  111. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/explanations.md +0 -0
  112. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/genindex.rst +0 -0
  113. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/choose-right-baseclass.md +0 -0
  114. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/contribute.md +0 -0
  115. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/implement-ad-detector.md +0 -0
  116. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/interact-with-signals.md +0 -0
  117. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/put-device-back.md +0 -0
  118. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to/store-and-retrieve.md +0 -0
  119. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/how-to.md +0 -0
  120. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/images/flyscan_collection_windows_and_frames.svg +0 -0
  121. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/images/ophyd-async-logo.svg +0 -0
  122. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/images/ophyd-favicon.svg +0 -0
  123. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  124. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/index.md +0 -0
  125. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/reference.md +0 -0
  126. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials/installation.md +0 -0
  127. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials/using-devices.md +0 -0
  128. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials/writing-tests-for-devices.md +0 -0
  129. {ophyd_async-0.10.1 → ophyd_async-0.11}/docs/tutorials.md +0 -0
  130. {ophyd_async-0.10.1 → ophyd_async-0.11}/setup.cfg +0 -0
  131. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/__init__.py +0 -0
  132. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/__main__.py +0 -0
  133. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/_docs_parser.py +0 -0
  134. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_device_filler.py +0 -0
  135. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_log.py +0 -0
  136. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  137. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_protocol.py +0 -0
  138. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_providers.py +0 -0
  139. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_readable.py +0 -0
  140. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_settings.py +0 -0
  141. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_signal_backend.py +0 -0
  142. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  143. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/core/_status.py +0 -0
  144. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/__init__.py +0 -0
  145. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  146. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  147. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  148. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
  149. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  150. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  151. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  152. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  153. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_core_logic.py +0 -0
  154. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
  155. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
  156. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  157. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
  158. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  159. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  160. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  161. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  162. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  163. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  164. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  165. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  166. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  167. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  168. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  169. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  170. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  171. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  172. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  173. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
  174. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  175. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/__init__.py +0 -0
  176. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_aioca.py +0 -0
  177. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  178. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  179. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_p4p.py +0 -0
  180. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  181. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_signal.py +0 -0
  182. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/core/_util.py +0 -0
  183. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/__init__.py +0 -0
  184. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/__main__.py +0 -0
  185. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  186. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/_motor.py +0 -0
  187. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  188. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  189. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/_stage.py +0 -0
  190. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/motor.db +0 -0
  191. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  192. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  193. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/eiger/__init__.py +0 -0
  194. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/signal.py +0 -0
  195. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/testing/__init__.py +0 -0
  196. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
  197. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/testing/_utils.py +0 -0
  198. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/testing/test_records.db +0 -0
  199. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  200. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/__init__.py +0 -0
  201. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/core.py +0 -0
  202. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
  203. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/eiger/_eiger_io.py +0 -0
  204. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  205. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  206. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_block.py +0 -0
  207. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  208. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  209. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  210. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  211. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  212. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  213. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  214. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  215. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  216. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  217. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  218. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/py.typed +0 -0
  219. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/__main__.py +0 -0
  220. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_blob_detector.py +0 -0
  221. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
  222. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_pattern_generator.py +0 -0
  223. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_point_detector.py +0 -0
  224. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/sim/_stage.py +0 -0
  225. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/__init__.py +0 -0
  226. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/__init__.py +0 -0
  227. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_base_device.py +0 -0
  228. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_converters.py +0 -0
  229. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_signal.py +0 -0
  230. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
  231. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
  232. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/core/_utils.py +0 -0
  233. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/__init__.py +0 -0
  234. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/_counter.py +0 -0
  235. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/_detector.py +0 -0
  236. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/_mover.py +0 -0
  237. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  238. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  239. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/testing/__init__.py +0 -0
  240. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  241. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/__init__.py +0 -0
  242. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  243. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_assert.py +0 -0
  244. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
  245. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  246. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_single_derived.py +0 -0
  247. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_utils.py +0 -0
  248. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  249. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  250. {ophyd_async-0.10.1 → ophyd_async-0.11}/src/ophyd_async.egg-info/top_level.txt +0 -0
  251. {ophyd_async-0.10.1 → ophyd_async-0.11}/system_tests/epics/eiger/README.md +0 -0
  252. {ophyd_async-0.10.1 → ophyd_async-0.11}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  253. {ophyd_async-0.10.1 → ophyd_async-0.11}/system_tests/epics/eiger/test_eiger_system.py +0 -0
  254. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/conftest.py +0 -0
  255. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_auto_init_devices.py +0 -0
  256. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_detector.py +0 -0
  257. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_log.py +0 -0
  258. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_mock_signal_backend.py +0 -0
  259. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_protocol.py +0 -0
  260. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_providers.py +0 -0
  261. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_readable.py +0 -0
  262. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_status.py +0 -0
  263. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_subset_enum.py +0 -0
  264. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_table.py +0 -0
  265. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_utils.py +0 -0
  266. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/core/test_watchable_async_status.py +0 -0
  267. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adandor/test_andor.py +0 -0
  268. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adaravis/test_aravis.py +0 -0
  269. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_detectors.py +0 -0
  270. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_single_trigger.py +0 -0
  271. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adcore/test_writers.py +0 -0
  272. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adkinetix/test_kinetix.py +0 -0
  273. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/adpilatus/test_pilatus.py +0 -0
  274. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/advimba/test_vimba.py +0 -0
  275. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/conftest.py +0 -0
  276. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/demo/test_epics_demo.py +0 -0
  277. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/eiger/test_odin_io.py +0 -0
  278. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/pvi/test_pvi.py +0 -0
  279. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/signal/test_common.py +0 -0
  280. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/signal/test_yaml_save_ca.yaml +0 -0
  281. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/signal/test_yaml_save_pva.yaml +0 -0
  282. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/epics/test_areadetector_subclass_naming.py +0 -0
  283. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/db/panda.db +0 -0
  284. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_hdf_panda.py +0 -0
  285. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_panda_control.py +0 -0
  286. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_panda_utils.py +0 -0
  287. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_seq_table.py +0 -0
  288. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_trigger.py +0 -0
  289. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/fastcs/panda/test_writer.py +0 -0
  290. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/plan_stubs/test_ensure_connected.py +0 -0
  291. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/plan_stubs/test_fly.py +0 -0
  292. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/plan_stubs/test_settings.py +0 -0
  293. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/plan_stubs/test_setup.py +0 -0
  294. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/sim/__init__.py +0 -0
  295. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/sim/test_sim_blob_detector.py +0 -0
  296. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/tango/conftest.py +0 -0
  297. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/tango/context_subprocess.py +0 -0
  298. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/test_cli.py +0 -0
  299. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/test_data/test_yaml_config_save.yaml +0 -0
  300. {ophyd_async-0.10.1 → ophyd_async-0.11}/tests/test_data/test_yaml_save.yaml +0 -0
@@ -22,6 +22,11 @@ jobs:
22
22
  runs-on: ${{ inputs.runs-on }}
23
23
 
24
24
  steps:
25
+ - name: Set TEMP to D:/Temp
26
+ if: inputs.runs-on == 'windows-latest'
27
+ run: |
28
+ mkdir "D:\\Temp"
29
+ echo "TEMP=D:\\Temp" >> $env:GITHUB_ENV
25
30
  - name: Checkout
26
31
  uses: actions/checkout@v4
27
32
  with:
@@ -49,10 +54,15 @@ jobs:
49
54
  with:
50
55
  python-version: ${{ inputs.python-version }}
51
56
  pip-install: ".[dev]"
57
+
58
+ - name: Run tests win
59
+ if: inputs.runs-on == 'windows-latest'
60
+ run: tox -e tests -- --timeout=6
52
61
 
53
- - name: Run tests
54
- run: tox -e tests
55
-
62
+ - name: Non win tests
63
+ if: inputs.runs-on != 'windows-latest'
64
+ run: tox -e tests -- --timeout=2
65
+
56
66
  - name: Upload coverage to Codecov
57
67
  uses: codecov/codecov-action@v4
58
68
  with:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.10.1
3
+ Version: 0.11
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
@@ -70,7 +70,7 @@ Requires-Dist: inflection; extra == "dev"
70
70
  Requires-Dist: import-linter; extra == "dev"
71
71
  Requires-Dist: myst-parser; extra == "dev"
72
72
  Requires-Dist: numpydoc; extra == "dev"
73
- Requires-Dist: ophyd; extra == "dev"
73
+ Requires-Dist: ophyd>=1.10.7; extra == "dev"
74
74
  Requires-Dist: pickleshare; extra == "dev"
75
75
  Requires-Dist: pipdeptree; extra == "dev"
76
76
  Requires-Dist: pre-commit; extra == "dev"
@@ -23,7 +23,7 @@ The `Device` class is the base of all ophyd-async objects that are published to
23
23
  - a [](#Device.parent) read-write property to read it's parent Device if it exists
24
24
  - a [](#Device.children) to iterate through the Device attributes, yielding the `(name, child)` child Devices
25
25
  - a `setattr` override that detects whether the attribute is also a Device and sets its parent
26
- - a [](#Device.set_name) method to set its name and also set the names of its children using the parent name as a prefix
26
+ - a [](#Device.set_name) method to set its name and also set the names of its children using the parent name as a prefix, called at init and also when a new child is attached to an already named Device
27
27
  - a [](#Device.connect) method that connects it and its children
28
28
 
29
29
  All the above methods are concrete, but `connect()` calls out to a [](#DeviceConnector) to actually do the connection, only handling caching itself. This enables plug-in behavior on connect (like the introspection of child Attributes in Tango or PVI, or the special case for `Signal` we will see later).
@@ -9,7 +9,7 @@ The simplest API involves mapping a single Derived Signal to many low level Sign
9
9
  - [`derived_signal_rw`](#ophyd_async.core.derived_signal_rw)
10
10
  - [`derived_signal_w`](#ophyd_async.core.derived_signal_w)
11
11
 
12
- If a signal is readable, then it requires a `raw_to_derived` function that maps the raw values of low level Signals into the datatype of the Derived Signal and the `raw_devices` that will be read/monitored to give those values.
12
+ If a signal is readable, then it requires a `raw_to_derived` function that maps the raw values of low level Signals into the datatype of the Derived Signal and the `raw_devices_and_constants` that will be read/monitored to give those values.
13
13
 
14
14
  If a signal is writeable, then it requires a `set_derived` async function that sets the raw signals based on the derived value.
15
15
 
@@ -27,7 +27,7 @@ These examples show the low level Signals and Derived Signals in the same Device
27
27
 
28
28
  The more general API involves a two way mapping between many Derived Signals and many low level Signals. This is done by implementing a `Raw` [](#typing.TypedDict) subclass with the names and datatypes of the low level Signals, a `Derived` [](#typing.TypedDict) subclass with the names and datatypes of the derived Signals, and [](#Transform) class with `raw_to_derived` and `derived_to_raw` methods to convert between the two. Some transforms will also require parameters which get their values from other Signals for both methods. These should be put in as type hints on the `Transform` subclass.
29
29
 
30
- To create the derived signals, we make a [](#DerivedSignalFactory) instance that knows about the `Transform` class, the `raw_devices` that will be read/monitored to provide the raw values for the transform, and optionally the `set_derived` method to set them. The methods like [](#DerivedSignalFactory.derived_signal_rw) allow Derived signals to be created for each attribute in the `Derived` TypedDict subclass.
30
+ To create the derived signals, we make a [](#DerivedSignalFactory) instance that knows about the `Transform` class, the `raw_devices_and_constants` that will be read/monitored to provide the raw values for the transform, and optionally the `set_derived` method to set them. The methods like [](#DerivedSignalFactory.derived_signal_rw) allow Derived signals to be created for each attribute in the `Derived` TypedDict subclass.
31
31
 
32
32
  In the below example we see this is action:
33
33
 
@@ -135,7 +135,7 @@ The above demonstrates the detector portion of a step scan, letting the things y
135
135
  @bpp.stage_decorator([bdet])
136
136
  @bpp.run_decorator()
137
137
  def fly_plan():
138
- yield from bps.prepare(bdet, TriggerInfo(number_of_triggers=7), wait=True)
138
+ yield from bps.prepare(bdet, TriggerInfo(number_of_events=7), wait=True)
139
139
  yield from bps.declare_stream(bdet, name="primary")
140
140
  yield from bps.kickoff(bdet, wait=True)
141
141
  yield from bps.collect_while_completing(flyers=[bdet], dets=[bdet], flush_period=0.5)
@@ -231,6 +231,7 @@ Finally, we need to communicate to bluesky that it has to `trigger()` and acquis
231
231
 
232
232
  Although the Signals are declared via type hints, the DeviceVector requires explicit instantiation in an `__init__` method. This is because it requires the `num_channels` to be passed in to the constructor to know how many channels require creation. This means that we also need to do the PV concatenation ourselves, so if the PV prefix for the device as `PREFIX:` then the first channel would have prefix `PREFIX:CHAN1:`. We also register them with `StandardReadable` in a different way, adding them within a [](#StandardReadable.add_children_as_readables) context manager which adds all the children created within its body.
233
233
 
234
+ Whilst it is not required for the call to `super().__init__` to be after all signals have been created it is more efficient to do so. However, there may be some edge cases where signals need to be created after this e.g. for [derived signals](../how-to/derive-one-signal-from-others.md) that depend on their parent.
234
235
  :::
235
236
 
236
237
  :::{tab-item} Tango
@@ -42,7 +42,7 @@ dev = [
42
42
  "import-linter",
43
43
  "myst-parser",
44
44
  "numpydoc",
45
- "ophyd",
45
+ "ophyd>=1.10.7",
46
46
  "pickleshare",
47
47
  "pipdeptree",
48
48
  "pre-commit",
@@ -101,7 +101,7 @@ markers = [
101
101
  ]
102
102
  asyncio_mode = "auto"
103
103
  asyncio_default_fixture_loop_scope = "function"
104
-
104
+ timeout = 0.5
105
105
  [tool.coverage.run]
106
106
  data_file = "/tmp/ophyd_async.coverage"
107
107
 
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.10.1'
21
- __version_tuple__ = version_tuple = (0, 10, 1)
20
+ __version__ = version = '0.11'
21
+ __version_tuple__ = version_tuple = (0, 11)
@@ -16,7 +16,7 @@ from ._detector import (
16
16
  )
17
17
  from ._device import Device, DeviceConnector, DeviceVector, init_devices
18
18
  from ._device_filler import DeviceFiller
19
- from ._flyer import FlyerController, StandardFlyer
19
+ from ._flyer import FlyerController, FlyMotorInfo, StandardFlyer
20
20
  from ._hdf_dataset import HDFDatasetDescription, HDFDocumentComposer
21
21
  from ._log import config_ophyd_async_logging
22
22
  from ._mock_signal_backend import MockSignalBackend
@@ -56,11 +56,14 @@ from ._signal import (
56
56
  soft_signal_rw,
57
57
  wait_for_value,
58
58
  walk_config_signals,
59
+ walk_devices,
59
60
  walk_rw_signals,
61
+ walk_signal_sources,
60
62
  )
61
63
  from ._signal_backend import (
62
64
  Array1D,
63
65
  DTypeScalar_co,
66
+ Primitive,
64
67
  SignalBackend,
65
68
  SignalDatatype,
66
69
  SignalDatatypeT,
@@ -75,6 +78,7 @@ from ._utils import (
75
78
  DEFAULT_TIMEOUT,
76
79
  CalculatableTimeout,
77
80
  Callback,
81
+ ConfinedModel,
78
82
  EnumTypes,
79
83
  LazyMock,
80
84
  NotConnected,
@@ -83,6 +87,7 @@ from ._utils import (
83
87
  SubsetEnum,
84
88
  SupersetEnum,
85
89
  WatcherUpdate,
90
+ error_if_none,
86
91
  gather_dict,
87
92
  get_dtype,
88
93
  get_enum_cls,
@@ -128,6 +133,7 @@ __all__ = [
128
133
  "EnumTypes",
129
134
  "Table",
130
135
  "SignalMetadata",
136
+ "Primitive",
131
137
  # Soft signal
132
138
  "SoftSignalBackend",
133
139
  "soft_signal_r_and_setter",
@@ -143,6 +149,8 @@ __all__ = [
143
149
  "set_and_wait_for_other_value",
144
150
  "walk_rw_signals",
145
151
  "walk_config_signals",
152
+ "walk_devices",
153
+ "walk_signal_sources",
146
154
  # Readable
147
155
  "StandardReadable",
148
156
  "StandardReadableFormat",
@@ -168,6 +176,7 @@ __all__ = [
168
176
  "HDFDocumentComposer",
169
177
  # Flyer
170
178
  "StandardFlyer",
179
+ "FlyMotorInfo",
171
180
  "FlyerController",
172
181
  # Settings
173
182
  "Settings",
@@ -179,8 +188,10 @@ __all__ = [
179
188
  "CalculatableTimeout",
180
189
  "DEFAULT_TIMEOUT",
181
190
  "Callback",
191
+ "ConfinedModel",
182
192
  "NotConnected",
183
193
  "Reference",
194
+ "error_if_none",
184
195
  "gather_dict",
185
196
  "get_dtype",
186
197
  "get_enum_cls",
@@ -11,7 +11,7 @@ from ._derived_signal_backend import (
11
11
  )
12
12
  from ._device import Device
13
13
  from ._signal import Signal, SignalR, SignalRW, SignalT, SignalW
14
- from ._signal_backend import SignalDatatypeT
14
+ from ._signal_backend import Primitive, SignalDatatypeT
15
15
 
16
16
 
17
17
  class DerivedSignalFactory(Generic[TransformT]):
@@ -23,18 +23,31 @@ class DerivedSignalFactory(Generic[TransformT]):
23
23
  :param set_derived:
24
24
  An optional async function that takes the output of
25
25
  `transform_cls.raw_to_derived` and applies it to the raw devices.
26
- :param raw_and_transform_devices:
27
- Devices whose values will be passed as parameters to the `transform_cls`,
28
- and as arguments to `transform_cls.raw_to_derived`.
26
+ :param raw_and_transform_devices_and_constants:
27
+ Devices and Constants whose values will be passed as parameters
28
+ to the `transform_cls`, and as arguments to `transform_cls.raw_to_derived`.
29
29
  """
30
30
 
31
31
  def __init__(
32
32
  self,
33
33
  transform_cls: type[TransformT],
34
34
  set_derived: Callable[..., Awaitable[None]] | None = None,
35
- **raw_and_transform_devices,
35
+ **raw_and_transform_devices_and_constants,
36
36
  ):
37
37
  self._set_derived = set_derived
38
+ _raw_and_transform_devices, _raw_and_transform_constants = (
39
+ {
40
+ k: v
41
+ for k, v in raw_and_transform_devices_and_constants.items()
42
+ if isinstance(v, Device)
43
+ },
44
+ {
45
+ k: v
46
+ for k, v in raw_and_transform_devices_and_constants.items()
47
+ if isinstance(v, Primitive)
48
+ },
49
+ )
50
+
38
51
  # Check the raw and transform devices match the input arguments of the Transform
39
52
  if transform_cls is not Transform:
40
53
  # Populate expected parameters and types
@@ -48,26 +61,42 @@ class DerivedSignalFactory(Generic[TransformT]):
48
61
  }
49
62
 
50
63
  # Populate received parameters and types
51
- # Use Signal datatype, or Locatable datatype, or set type as None
64
+ # Use Primitive's type, Signal's datatype,
65
+ # Locatable's datatype, or set type as None
52
66
  received = {
53
- k: v.datatype if isinstance(v, Signal) else get_locatable_type(v)
54
- for k, v in raw_and_transform_devices.items()
67
+ **{
68
+ k: v.datatype if isinstance(v, Signal) else get_locatable_type(v)
69
+ for k, v in _raw_and_transform_devices.items()
70
+ },
71
+ **{k: type(v) for k, v in _raw_and_transform_constants.items()},
55
72
  }
56
73
 
57
74
  if expected != received:
58
75
  msg = (
59
- f"Expected devices to be passed as keyword arguments "
76
+ f"Expected the following to be passed as keyword arguments "
60
77
  f"{expected}, got {received}"
61
78
  )
62
79
  raise TypeError(msg)
63
80
  self._set_derived_takes_dict = (
64
81
  is_typeddict(_get_first_arg_datatype(set_derived)) if set_derived else False
65
82
  )
83
+
84
+ _raw_constants, _transform_constants = _partition_by_keys(
85
+ _raw_and_transform_constants, set(transform_cls.model_fields)
86
+ )
87
+
88
+ _raw_devices, _transform_devices = _partition_by_keys(
89
+ _raw_and_transform_devices, set(transform_cls.model_fields)
90
+ )
91
+
66
92
  self._transformer = SignalTransformer(
67
93
  transform_cls,
68
94
  set_derived,
69
95
  self._set_derived_takes_dict,
70
- **raw_and_transform_devices,
96
+ _raw_devices,
97
+ _raw_constants,
98
+ _transform_devices,
99
+ _transform_constants,
71
100
  )
72
101
 
73
102
  def _make_signal(
@@ -177,7 +206,7 @@ def _get_first_arg_datatype(
177
206
  def _make_factory(
178
207
  raw_to_derived: Callable[..., SignalDatatypeT] | None = None,
179
208
  set_derived: Callable[[SignalDatatypeT], Awaitable[None]] | None = None,
180
- raw_devices: dict[str, Device] | None = None,
209
+ raw_devices_and_constants: dict[str, Device | Primitive] | None = None,
181
210
  ) -> DerivedSignalFactory:
182
211
  if raw_to_derived:
183
212
 
@@ -190,7 +219,9 @@ def _make_factory(
190
219
  DerivedTransform.raw_to_derived.__annotations__ = get_type_hints(raw_to_derived)
191
220
 
192
221
  return DerivedSignalFactory(
193
- DerivedTransform, set_derived=set_derived, **(raw_devices or {})
222
+ DerivedTransform,
223
+ set_derived=set_derived,
224
+ **(raw_devices_and_constants or {}),
194
225
  )
195
226
  else:
196
227
  return DerivedSignalFactory(Transform, set_derived=set_derived)
@@ -200,7 +231,7 @@ def derived_signal_r(
200
231
  raw_to_derived: Callable[..., SignalDatatypeT],
201
232
  derived_units: str | None = None,
202
233
  derived_precision: int | None = None,
203
- **raw_devices: Device,
234
+ **raw_devices_and_constants: Device | Primitive,
204
235
  ) -> SignalR[SignalDatatypeT]:
205
236
  """Create a read only derived signal.
206
237
 
@@ -209,11 +240,14 @@ def derived_signal_r(
209
240
  returns the derived value.
210
241
  :param derived_units: Engineering units for the derived signal
211
242
  :param derived_precision: Number of digits after the decimal place to display
212
- :param raw_devices:
213
- A dictionary of Devices to provide the values for raw_to_derived. The names
214
- of these arguments must match the arguments of raw_to_derived.
243
+ :param raw_devices_and_constants:
244
+ A dictionary of Devices and Constants to provide the values for raw_to_derived.
245
+ The names of these arguments must match the arguments of raw_to_derived.
215
246
  """
216
- factory = _make_factory(raw_to_derived=raw_to_derived, raw_devices=raw_devices)
247
+ factory = _make_factory(
248
+ raw_to_derived=raw_to_derived,
249
+ raw_devices_and_constants=raw_devices_and_constants,
250
+ )
217
251
  return factory.derived_signal_r(
218
252
  datatype=_get_return_datatype(raw_to_derived),
219
253
  name="value",
@@ -227,7 +261,7 @@ def derived_signal_rw(
227
261
  set_derived: Callable[[SignalDatatypeT], Awaitable[None]],
228
262
  derived_units: str | None = None,
229
263
  derived_precision: int | None = None,
230
- **raw_devices: Device,
264
+ **raw_devices_and_constants: Device | Primitive,
231
265
  ) -> SignalRW[SignalDatatypeT]:
232
266
  """Create a read-write derived signal.
233
267
 
@@ -239,9 +273,9 @@ def derived_signal_rw(
239
273
  either be an async function, or return an [](#AsyncStatus)
240
274
  :param derived_units: Engineering units for the derived signal
241
275
  :param derived_precision: Number of digits after the decimal place to display
242
- :param raw_devices:
243
- A dictionary of Devices to provide the values for raw_to_derived. The names
244
- of these arguments must match the arguments of raw_to_derived.
276
+ :param raw_devices_and_constants:
277
+ A dictionary of Devices and Constants to provide the values for raw_to_derived.
278
+ The names of these arguments must match the arguments of raw_to_derived.
245
279
  """
246
280
  raw_to_derived_datatype = _get_return_datatype(raw_to_derived)
247
281
  set_derived_datatype = _get_first_arg_datatype(set_derived)
@@ -253,7 +287,9 @@ def derived_signal_rw(
253
287
  raise TypeError(msg)
254
288
 
255
289
  factory = _make_factory(
256
- raw_to_derived=raw_to_derived, set_derived=set_derived, raw_devices=raw_devices
290
+ raw_to_derived=raw_to_derived,
291
+ set_derived=set_derived,
292
+ raw_devices_and_constants=raw_devices_and_constants,
257
293
  )
258
294
  return factory.derived_signal_rw(
259
295
  datatype=raw_to_derived_datatype,
@@ -297,3 +333,13 @@ def get_locatable_type(obj: object) -> type | None:
297
333
  if args:
298
334
  return args[0]
299
335
  return None
336
+
337
+
338
+ def _partition_by_keys(data: dict, keys: set) -> tuple[dict, dict]:
339
+ group_excluded, group_included = {}, {}
340
+ for k, v in data.items():
341
+ if k in keys:
342
+ group_included[k] = v
343
+ else:
344
+ group_excluded[k] = v
345
+ return group_excluded, group_included
@@ -7,17 +7,23 @@ from typing import TYPE_CHECKING, Any, Generic, TypeVar
7
7
 
8
8
  from bluesky.protocols import Location, Reading, Subscribable
9
9
  from event_model import DataKey
10
- from pydantic import BaseModel
11
10
 
12
11
  from ._protocol import AsyncLocatable, AsyncReadable
13
12
  from ._signal_backend import SignalBackend, SignalDatatypeT, make_datakey, make_metadata
14
- from ._utils import Callback, T, gather_dict, merge_gathered_dicts
13
+ from ._utils import (
14
+ Callback,
15
+ ConfinedModel,
16
+ T,
17
+ error_if_none,
18
+ gather_dict,
19
+ merge_gathered_dicts,
20
+ )
15
21
 
16
22
  RawT = TypeVar("RawT")
17
23
  DerivedT = TypeVar("DerivedT")
18
24
 
19
25
 
20
- class Transform(BaseModel, Generic[RawT, DerivedT]):
26
+ class Transform(ConfinedModel, Generic[RawT, DerivedT]):
21
27
  """Baseclass for bidirectional transforms for Derived Signals.
22
28
 
23
29
  Subclass and add:
@@ -77,15 +83,20 @@ class SignalTransformer(Generic[TransformT]):
77
83
  transform_cls: type[TransformT],
78
84
  set_derived: Callable[..., Awaitable[None]] | None,
79
85
  set_derived_takes_dict: bool,
80
- **raw_and_transform_devices,
86
+ raw_devices,
87
+ raw_constants,
88
+ transform_devices,
89
+ transform_constants,
81
90
  ):
82
91
  self._transform_cls = transform_cls
83
92
  self._set_derived = set_derived
84
93
  self._set_derived_takes_dict = set_derived_takes_dict
85
- self._transform_devices = {
86
- k: raw_and_transform_devices.pop(k) for k in transform_cls.model_fields
87
- }
88
- self._raw_devices = raw_and_transform_devices
94
+
95
+ self._transform_devices = transform_devices
96
+ self._transform_constants = transform_constants
97
+ self._raw_devices = raw_devices
98
+ self._raw_constants = raw_constants
99
+
89
100
  self._derived_callbacks: dict[str, Callback[Reading]] = {}
90
101
  self._cached_readings: dict[str, Reading] | None = None
91
102
 
@@ -124,7 +135,7 @@ class SignalTransformer(Generic[TransformT]):
124
135
  k: transform_readings[sig.name]["value"]
125
136
  for k, sig in self.transform_readables.items()
126
137
  }
127
- return self._transform_cls(**transform_args)
138
+ return self._transform_cls(**(transform_args | self._transform_constants))
128
139
 
129
140
  def _make_derived_readings(
130
141
  self, raw_and_transform_readings: dict[str, Reading]
@@ -142,10 +153,15 @@ class SignalTransformer(Generic[TransformT]):
142
153
  transform = self._make_transform_from_readings(raw_and_transform_readings)
143
154
  # Create the raw values from the rest then calculate the derived readings
144
155
  # using the transform
156
+ # Extend dictionary with values of any Constants passed as arguments
145
157
  raw_values = {
146
- k: raw_and_transform_readings[sig.name]["value"]
147
- for k, sig in self._raw_devices.items()
158
+ **{
159
+ k: raw_and_transform_readings[sig.name]["value"]
160
+ for k, sig in self._raw_devices.items()
161
+ },
162
+ **self._raw_constants,
148
163
  }
164
+
149
165
  derived_readings = {
150
166
  name: Reading(
151
167
  value=derived, timestamp=timestamp, alarm_severity=alarm_severity
@@ -175,13 +191,15 @@ class SignalTransformer(Generic[TransformT]):
175
191
  return {k: v["value"] for k, v in derived_readings.items()}
176
192
 
177
193
  def _update_cached_reading(self, value: dict[str, Reading]):
178
- if self._cached_readings is None:
179
- msg = "Cannot update cached reading as it has not been initialised"
180
- raise RuntimeError(msg)
181
- self._cached_readings.update(value)
194
+ _cached_readings = error_if_none(
195
+ self._cached_readings,
196
+ "Cannot update cached reading as it has not been initialised",
197
+ )
198
+
199
+ _cached_readings.update(value)
182
200
  if self._complete_cached_reading():
183
201
  # We've got a complete set of values, callback on them
184
- derived_readings = self._make_derived_readings(self._cached_readings)
202
+ derived_readings = self._make_derived_readings(_cached_readings)
185
203
  for name, callback in self._derived_callbacks.items():
186
204
  callback(derived_readings[name])
187
205
 
@@ -228,18 +246,19 @@ class SignalTransformer(Generic[TransformT]):
228
246
  }
229
247
 
230
248
  async def set_derived(self, name: str, value: Any):
231
- if self._set_derived is None:
232
- msg = "Cannot put as no set_derived method given"
233
- raise RuntimeError(msg)
249
+ _set_derived = error_if_none(
250
+ self._set_derived,
251
+ "Cannot put as no set_derived method given",
252
+ )
234
253
  if self._set_derived_takes_dict:
235
254
  # Need to get the other derived values and update the one that's changing
236
255
  derived = await self.get_locations()
237
256
  setpoints = {k: v["setpoint"] for k, v in derived.items()}
238
257
  setpoints[name] = value
239
- await self._set_derived(setpoints)
258
+ await _set_derived(setpoints)
240
259
  else:
241
260
  # Only one derived signal, so pass it directly
242
- await self._set_derived(value)
261
+ await _set_derived(value)
243
262
 
244
263
 
245
264
  class DerivedSignalBackend(SignalBackend[SignalDatatypeT]):
@@ -275,9 +294,12 @@ class DerivedSignalBackend(SignalBackend[SignalDatatypeT]):
275
294
  if wait is False:
276
295
  msg = "Cannot put with wait=False"
277
296
  raise RuntimeError(msg)
278
- if value is None:
279
- msg = "Must be given a value to put"
280
- raise RuntimeError(msg)
297
+
298
+ value = error_if_none(
299
+ value,
300
+ "Must be given a value to put",
301
+ )
302
+
281
303
  await self.transformer.set_derived(self.name, value)
282
304
 
283
305
  async def get_datakey(self, source: str) -> DataKey:
@@ -23,13 +23,13 @@ from bluesky.protocols import (
23
23
  WritesStreamAssets,
24
24
  )
25
25
  from event_model import DataKey
26
- from pydantic import BaseModel, Field, NonNegativeInt, PositiveInt, computed_field
26
+ from pydantic import Field, NonNegativeInt, PositiveInt, computed_field
27
27
 
28
28
  from ._device import Device, DeviceConnector
29
29
  from ._protocol import AsyncConfigurable, AsyncReadable
30
30
  from ._signal import SignalR
31
31
  from ._status import AsyncStatus, WatchableAsyncStatus
32
- from ._utils import DEFAULT_TIMEOUT, WatcherUpdate, merge_gathered_dicts
32
+ from ._utils import DEFAULT_TIMEOUT, ConfinedModel, WatcherUpdate, merge_gathered_dicts
33
33
 
34
34
 
35
35
  class DetectorTrigger(Enum):
@@ -48,7 +48,7 @@ class DetectorTrigger(Enum):
48
48
  """Expect a series of variable width external gate signals"""
49
49
 
50
50
 
51
- class TriggerInfo(BaseModel):
51
+ class TriggerInfo(ConfinedModel):
52
52
  """Minimal set of information required to setup triggering on a detector."""
53
53
 
54
54
  number_of_events: NonNegativeInt | list[NonNegativeInt] = Field(default=1)
@@ -10,7 +10,13 @@ from typing import Any, TypeVar
10
10
  from bluesky.protocols import HasName
11
11
  from bluesky.run_engine import call_in_bluesky_event_loop, in_bluesky_event_loop
12
12
 
13
- from ._utils import DEFAULT_TIMEOUT, LazyMock, NotConnected, wait_for_connection
13
+ from ._utils import (
14
+ DEFAULT_TIMEOUT,
15
+ LazyMock,
16
+ NotConnected,
17
+ error_if_none,
18
+ wait_for_connection,
19
+ )
14
20
 
15
21
 
16
22
  class DeviceConnector:
@@ -148,6 +154,10 @@ class Device(HasName):
148
154
  elif name not in _not_device_attrs and isinstance(value, Device):
149
155
  value.parent = self
150
156
  self._child_devices[name] = value
157
+ # And if the name is set, then set the name of all children,
158
+ # including the child
159
+ if self._name:
160
+ self.set_name(self._name)
151
161
  # ...and avoiding the super call as we know it resolves to `object`
152
162
  return object.__setattr__(self, name, value)
153
163
 
@@ -171,12 +181,11 @@ class Device(HasName):
171
181
  :param force_reconnect:
172
182
  If True, force a reconnect even if the last connect succeeded.
173
183
  """
174
- if not hasattr(self, "_connector"):
175
- msg = (
176
- f"{self}: doesn't have attribute `_connector`,"
177
- " did you call `super().__init__` in your `__init__` method?"
178
- )
179
- raise RuntimeError(msg)
184
+ connector = error_if_none(
185
+ getattr(self, "_connector", None),
186
+ f"{self}: doesn't have attribute `_connector`,"
187
+ f" did you call `super().__init__` in your `__init__` method?",
188
+ )
180
189
  if mock:
181
190
  # Always connect in mock mode serially
182
191
  if isinstance(mock, LazyMock):
@@ -185,7 +194,7 @@ class Device(HasName):
185
194
  elif not self._mock:
186
195
  # Make one
187
196
  self._mock = LazyMock()
188
- await self._connector.connect_mock(self, self._mock)
197
+ await connector.connect_mock(self, self._mock)
189
198
  else:
190
199
  # Try to cache the connect in real mode
191
200
  can_use_previous_connect = (
@@ -195,13 +204,13 @@ class Device(HasName):
195
204
  )
196
205
  if force_reconnect or not can_use_previous_connect:
197
206
  self._mock = None
198
- coro = self._connector.connect_real(self, timeout, force_reconnect)
207
+ coro = connector.connect_real(self, timeout, force_reconnect)
199
208
  self._connect_task = asyncio.create_task(coro)
200
- if not self._connect_task:
201
- msg = "Connect task not created, this shouldn't happen"
202
- raise RuntimeError(msg)
209
+ connect_task = error_if_none(
210
+ self._connect_task, "Connect task not created, this shouldn't happen"
211
+ )
203
212
  # Wait for it to complete
204
- await self._connect_task
213
+ await connect_task
205
214
 
206
215
 
207
216
  _not_device_attrs = {
@@ -289,9 +298,8 @@ class DeviceProcessor:
289
298
  raise ValueError
290
299
  except ValueError:
291
300
  _, _, tb = sys.exc_info()
292
- if not tb:
293
- msg = "Can't get traceback, this shouldn't happen"
294
- raise RuntimeError(msg) # noqa: B904
301
+ tb = error_if_none(tb, "Can't get traceback, this shouldn't happen")
302
+
295
303
  caller_frame = tb.tb_frame
296
304
  while caller_frame.f_locals.get("self", None) is self:
297
305
  caller_frame = caller_frame.f_back