ophyd-async 0.10.0a1__tar.gz → 0.10.0a3__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 (299) hide show
  1. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/PKG-INFO +1 -1
  2. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/_version.py +2 -2
  3. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/__init__.py +0 -2
  4. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_derived_signal.py +6 -6
  5. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_derived_signal_backend.py +4 -4
  6. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_detector.py +69 -55
  7. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_device.py +3 -3
  8. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_hdf_dataset.py +1 -5
  9. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_providers.py +0 -8
  10. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_readable.py +13 -1
  11. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_table.py +4 -3
  12. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adandor/_andor_controller.py +1 -1
  13. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adaravis/_aravis_controller.py +2 -2
  14. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_core_logic.py +3 -3
  15. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_core_writer.py +22 -29
  16. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_hdf_writer.py +17 -15
  17. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_jpeg_writer.py +1 -3
  18. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_tiff_writer.py +1 -3
  19. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +1 -1
  20. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +2 -2
  21. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +1 -1
  22. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/advimba/_vimba_controller.py +1 -1
  23. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_p4p.py +1 -1
  24. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_pvi_connector.py +5 -3
  25. ophyd_async-0.10.0a3/src/ophyd_async/epics/eiger/__init__.py +3 -0
  26. ophyd_async-0.10.0a3/src/ophyd_async/epics/eiger/_odin_io.py +148 -0
  27. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/testing/_example_ioc.py +1 -0
  28. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/testing/test_records.db +5 -0
  29. ophyd_async-0.10.0a3/src/ophyd_async/fastcs/eiger/__init__.py +13 -0
  30. {ophyd_async-0.10.0a1/src/ophyd_async/epics → ophyd_async-0.10.0a3/src/ophyd_async/fastcs}/eiger/_eiger.py +5 -5
  31. {ophyd_async-0.10.0a1/src/ophyd_async/epics → ophyd_async-0.10.0a3/src/ophyd_async/fastcs}/eiger/_eiger_controller.py +12 -26
  32. ophyd_async-0.10.0a3/src/ophyd_async/fastcs/eiger/_eiger_io.py +53 -0
  33. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_block.py +2 -0
  34. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -1
  35. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_writer.py +23 -22
  36. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_fly.py +2 -2
  37. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_blob_detector.py +0 -1
  38. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_blob_detector_controller.py +1 -1
  39. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_blob_detector_writer.py +15 -19
  40. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_pattern_generator.py +2 -0
  41. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_assert.py +21 -15
  42. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_single_derived.py +2 -0
  43. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async.egg-info/PKG-INFO +1 -1
  44. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async.egg-info/SOURCES.txt +6 -5
  45. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/system_tests/epics/eiger/test_eiger_system.py +2 -2
  46. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/conftest.py +7 -2
  47. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_detector.py +19 -13
  48. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_flyer.py +30 -26
  49. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_readable.py +17 -0
  50. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_signal.py +14 -0
  51. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_single_derived_signal.py +15 -0
  52. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adandor/test_andor.py +2 -2
  53. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adaravis/test_aravis.py +2 -2
  54. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_detectors.py +3 -4
  55. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_scans.py +2 -3
  56. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_writers.py +52 -13
  57. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adkinetix/test_kinetix.py +1 -1
  58. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adpilatus/test_pilatus.py +7 -6
  59. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adsimdetector/test_sim.py +182 -22
  60. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/advimba/test_vimba.py +1 -1
  61. ophyd_async-0.10.0a3/tests/epics/eiger/test_odin_io.py +106 -0
  62. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/pvi/test_pvi.py +30 -0
  63. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/signal/test_signals.py +43 -0
  64. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/signal/test_yaml_save_ca.yaml +1 -0
  65. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/signal/test_yaml_save_pva.yaml +1 -0
  66. {ophyd_async-0.10.0a1/tests/epics → ophyd_async-0.10.0a3/tests/fastcs}/eiger/test_eiger_controller.py +18 -36
  67. {ophyd_async-0.10.0a1/tests/epics → ophyd_async-0.10.0a3/tests/fastcs}/eiger/test_eiger_detector.py +10 -12
  68. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/db/panda.db +27 -0
  69. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_hdf_panda.py +1 -2
  70. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_panda_control.py +3 -3
  71. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_panda_utils.py +4 -0
  72. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_writer.py +17 -20
  73. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/plan_stubs/test_fly.py +17 -11
  74. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/sim/test_sim_blob_detector.py +4 -2
  75. ophyd_async-0.10.0a1/src/ophyd_async/epics/eiger/__init__.py +0 -5
  76. ophyd_async-0.10.0a1/src/ophyd_async/epics/eiger/_eiger_io.py +0 -42
  77. ophyd_async-0.10.0a1/src/ophyd_async/epics/eiger/_odin_io.py +0 -125
  78. ophyd_async-0.10.0a1/tests/epics/eiger/test_odin_io.py +0 -63
  79. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.codecov.yml +0 -0
  80. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.copier-answers.yml +0 -0
  81. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.devcontainer/devcontainer.json +0 -0
  82. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.git-blame-ignore-revs +0 -0
  83. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/CONTRIBUTING.md +0 -0
  84. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  85. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  86. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  87. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/actions/install_requirements/action.yml +0 -0
  88. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/codeql/codeql-config.yml +0 -0
  89. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/dependabot.yml +0 -0
  90. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/pages/index.html +0 -0
  91. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/pages/make_switcher.py +0 -0
  92. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_check.yml +0 -0
  93. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_codeql.yml +0 -0
  94. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_dist.yml +0 -0
  95. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_docs.yml +0 -0
  96. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_import_with_no_extras.yml +0 -0
  97. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_pypi.yml +0 -0
  98. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_release.yml +0 -0
  99. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_test.yml +0 -0
  100. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/_tox.yml +0 -0
  101. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/ci.yml +0 -0
  102. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.github/workflows/periodic.yml +0 -0
  103. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.gitignore +0 -0
  104. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/.pre-commit-config.yaml +0 -0
  105. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/Dockerfile +0 -0
  106. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/LICENSE +0 -0
  107. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/README.md +0 -0
  108. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/_static/custom.css +0 -0
  109. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/conf.py +0 -0
  110. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  111. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  112. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  113. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  114. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  115. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  116. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  117. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0008-signal-types.md +0 -0
  118. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  119. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  120. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions/COPYME +0 -0
  121. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/decisions.md +0 -0
  122. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/declarative-vs-procedural.md +0 -0
  123. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/design-goals.md +0 -0
  124. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/device-connection-strategies.md +0 -0
  125. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/devices-signals-backends.md +0 -0
  126. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/flyscanning.md +0 -0
  127. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations/where-device-logic.md +0 -0
  128. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/explanations.md +0 -0
  129. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/genindex.rst +0 -0
  130. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/choose-right-baseclass.md +0 -0
  131. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/contribute.md +0 -0
  132. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/derive-one-signal-from-others.md +0 -0
  133. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/implement-ad-detector.md +0 -0
  134. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/interact-with-signals.md +0 -0
  135. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/put-device-back.md +0 -0
  136. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to/store-and-retrieve.md +0 -0
  137. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/how-to.md +0 -0
  138. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/images/flyscan_collection_windows_and_frames.svg +0 -0
  139. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/images/ophyd-async-logo.svg +0 -0
  140. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/images/ophyd-favicon.svg +0 -0
  141. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  142. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/index.md +0 -0
  143. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/reference.md +0 -0
  144. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials/implementing-detectors.md +0 -0
  145. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials/implementing-devices.md +0 -0
  146. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials/installation.md +0 -0
  147. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials/using-devices.md +0 -0
  148. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials/writing-tests-for-devices.md +0 -0
  149. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/docs/tutorials.md +0 -0
  150. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/pyproject.toml +0 -0
  151. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/setup.cfg +0 -0
  152. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/__init__.py +0 -0
  153. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/__main__.py +0 -0
  154. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/_docs_parser.py +0 -0
  155. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_device_filler.py +0 -0
  156. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_flyer.py +0 -0
  157. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_log.py +0 -0
  158. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  159. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_protocol.py +0 -0
  160. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_settings.py +0 -0
  161. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_signal.py +0 -0
  162. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_signal_backend.py +0 -0
  163. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  164. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_status.py +0 -0
  165. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_utils.py +0 -0
  166. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/core/_yaml_settings.py +0 -0
  167. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/__init__.py +0 -0
  168. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adandor/__init__.py +0 -0
  169. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  170. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
  171. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  172. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  173. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  174. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  175. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  176. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  177. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  178. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  179. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  180. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  181. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  182. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  183. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  184. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  185. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  186. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  187. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  188. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  189. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  190. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  191. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/__init__.py +0 -0
  192. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_aioca.py +0 -0
  193. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  194. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  195. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_signal.py +0 -0
  196. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/core/_util.py +0 -0
  197. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/__init__.py +0 -0
  198. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/__main__.py +0 -0
  199. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  200. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/_motor.py +0 -0
  201. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  202. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  203. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/_stage.py +0 -0
  204. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/motor.db +0 -0
  205. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  206. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  207. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/motor.py +0 -0
  208. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/signal.py +0 -0
  209. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/testing/__init__.py +0 -0
  210. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/testing/_utils.py +0 -0
  211. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  212. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/__init__.py +0 -0
  213. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/core.py +0 -0
  214. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  215. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  216. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_control.py +0 -0
  217. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  218. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
  219. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  220. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  221. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  222. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  223. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  224. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  225. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  226. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/py.typed +0 -0
  227. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/__init__.py +0 -0
  228. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/__main__.py +0 -0
  229. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
  230. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
  231. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_motor.py +0 -0
  232. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_point_detector.py +0 -0
  233. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/sim/_stage.py +0 -0
  234. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/__init__.py +0 -0
  235. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/__init__.py +0 -0
  236. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_base_device.py +0 -0
  237. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_converters.py +0 -0
  238. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_signal.py +0 -0
  239. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_tango_readable.py +0 -0
  240. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_tango_transport.py +0 -0
  241. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/core/_utils.py +0 -0
  242. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/__init__.py +0 -0
  243. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/_counter.py +0 -0
  244. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/_detector.py +0 -0
  245. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/_mover.py +0 -0
  246. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  247. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  248. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/testing/__init__.py +0 -0
  249. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  250. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/__init__.py +0 -0
  251. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  252. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_mock_signal_utils.py +0 -0
  253. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  254. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_utils.py +0 -0
  255. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  256. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  257. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async.egg-info/requires.txt +0 -0
  258. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/src/ophyd_async.egg-info/top_level.txt +0 -0
  259. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/system_tests/epics/eiger/README.md +0 -0
  260. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  261. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_auto_init_devices.py +0 -0
  262. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_device.py +0 -0
  263. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_log.py +0 -0
  264. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_mock_signal_backend.py +0 -0
  265. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_multi_derived_signal.py +0 -0
  266. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_observe.py +0 -0
  267. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_protocol.py +0 -0
  268. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_providers.py +0 -0
  269. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_soft_signal_backend.py +0 -0
  270. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_status.py +0 -0
  271. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_subset_enum.py +0 -0
  272. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_table.py +0 -0
  273. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_utils.py +0 -0
  274. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/core/test_watchable_async_status.py +0 -0
  275. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_cont_acq_detector.py +0 -0
  276. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_drivers.py +0 -0
  277. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/adcore/test_single_trigger.py +0 -0
  278. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/conftest.py +0 -0
  279. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/demo/test_epics_demo.py +0 -0
  280. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/signal/test_common.py +0 -0
  281. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/test_areadetector_subclass_naming.py +0 -0
  282. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/epics/test_motor.py +0 -0
  283. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_panda_connect.py +0 -0
  284. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_seq_table.py +0 -0
  285. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/fastcs/panda/test_trigger.py +0 -0
  286. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/plan_stubs/test_ensure_connected.py +0 -0
  287. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/plan_stubs/test_settings.py +0 -0
  288. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/plan_stubs/test_setup.py +0 -0
  289. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/sim/__init__.py +0 -0
  290. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/sim/test_sim_motor.py +0 -0
  291. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/tango/conftest.py +0 -0
  292. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/tango/context_subprocess.py +0 -0
  293. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/tango/test_base_device.py +0 -0
  294. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/tango/test_tango_signals.py +0 -0
  295. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/tango/test_tango_transport.py +0 -0
  296. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/test_cli.py +0 -0
  297. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/test_data/test_yaml_config_save.yaml +0 -0
  298. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/test_data/test_yaml_save.yaml +0 -0
  299. {ophyd_async-0.10.0a1 → ophyd_async-0.10.0a3}/tests/test_tutorials.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.10.0a1
3
+ Version: 0.10.0a3
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
@@ -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.0a1'
21
- __version_tuple__ = version_tuple = (0, 10, 0)
20
+ __version__ = version = '0.10.0a3'
21
+ __version_tuple__ = version_tuple = (0, 10, 0, 'a3')
@@ -26,7 +26,6 @@ from ._providers import (
26
26
  AutoIncrementingPathProvider,
27
27
  DatasetDescriber,
28
28
  FilenameProvider,
29
- NameProvider,
30
29
  PathInfo,
31
30
  PathProvider,
32
31
  StaticFilenameProvider,
@@ -160,7 +159,6 @@ __all__ = [
160
159
  "AutoIncrementFilenameProvider",
161
160
  "UUIDFilenameProvider",
162
161
  # Datatset
163
- "NameProvider",
164
162
  "DatasetDescriber",
165
163
  "HDFDatasetDescription",
166
164
  "HDFDocumentComposer",
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Awaitable, Callable
2
- from typing import Any, Generic, get_type_hints
2
+ from typing import Any, Generic, get_type_hints, is_typeddict
3
3
 
4
4
  from ._derived_signal_backend import (
5
5
  DerivedSignalBackend,
@@ -46,13 +46,13 @@ class DerivedSignalFactory(Generic[TransformT]):
46
46
  f"got {list(raw_and_transform_devices)}"
47
47
  )
48
48
  raise TypeError(msg)
49
- set_derived_datatype = (
50
- _get_first_arg_datatype(set_derived) if set_derived else None
49
+ self._set_derived_takes_dict = (
50
+ is_typeddict(_get_first_arg_datatype(set_derived)) if set_derived else False
51
51
  )
52
52
  self._transformer = SignalTransformer(
53
53
  transform_cls,
54
54
  set_derived,
55
- set_derived_datatype,
55
+ self._set_derived_takes_dict,
56
56
  **raw_and_transform_devices,
57
57
  )
58
58
 
@@ -75,7 +75,7 @@ class DerivedSignalFactory(Generic[TransformT]):
75
75
  f"{signal_cls.__name__}s"
76
76
  )
77
77
  raise ValueError(msg)
78
- if issubclass(signal_cls, SignalRW):
78
+ if issubclass(signal_cls, SignalRW) and self._set_derived_takes_dict:
79
79
  self._transformer.raw_locatables # noqa: B018
80
80
  backend = DerivedSignalBackend(
81
81
  datatype, name, self._transformer, units, precision
@@ -173,7 +173,7 @@ def _make_factory(
173
173
 
174
174
  # Update the signature for raw_to_derived to match what we are passed as this
175
175
  # will be checked in DerivedSignalFactory
176
- DerivedTransform.raw_to_derived.__annotations__ = raw_to_derived.__annotations__
176
+ DerivedTransform.raw_to_derived.__annotations__ = get_type_hints(raw_to_derived)
177
177
 
178
178
  return DerivedSignalFactory(
179
179
  DerivedTransform, set_derived=set_derived, **(raw_devices or {})
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  from collections.abc import Awaitable, Callable, Mapping
5
5
  from functools import cached_property
6
- from typing import TYPE_CHECKING, Any, Generic, TypeVar, is_typeddict
6
+ 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
@@ -76,12 +76,12 @@ class SignalTransformer(Generic[TransformT]):
76
76
  self,
77
77
  transform_cls: type[TransformT],
78
78
  set_derived: Callable[..., Awaitable[None]] | None,
79
- set_derived_datatype: type | None,
79
+ set_derived_takes_dict: bool,
80
80
  **raw_and_transform_devices,
81
81
  ):
82
82
  self._transform_cls = transform_cls
83
83
  self._set_derived = set_derived
84
- self._need_dict = is_typeddict(set_derived_datatype)
84
+ self._set_derived_takes_dict = set_derived_takes_dict
85
85
  self._transform_devices = {
86
86
  k: raw_and_transform_devices.pop(k) for k in transform_cls.model_fields
87
87
  }
@@ -229,7 +229,7 @@ class SignalTransformer(Generic[TransformT]):
229
229
  if self._set_derived is None:
230
230
  msg = "Cannot put as no set_derived method given"
231
231
  raise RuntimeError(msg)
232
- if self._need_dict:
232
+ if self._set_derived_takes_dict:
233
233
  # Need to get the other derived values and update the one that's changing
234
234
  derived = await self.get_locations()
235
235
  setpoints = {k: v["setpoint"] for k, v in derived.items()}
@@ -23,7 +23,7 @@ from bluesky.protocols import (
23
23
  WritesStreamAssets,
24
24
  )
25
25
  from event_model import DataKey
26
- from pydantic import BaseModel, Field, NonNegativeInt, computed_field
26
+ from pydantic import BaseModel, Field, NonNegativeInt, PositiveInt, computed_field
27
27
 
28
28
  from ._device import Device, DeviceConnector
29
29
  from ._protocol import AsyncConfigurable, AsyncReadable
@@ -51,49 +51,52 @@ class DetectorTrigger(Enum):
51
51
  class TriggerInfo(BaseModel):
52
52
  """Minimal set of information required to setup triggering on a detector."""
53
53
 
54
- number_of_triggers: NonNegativeInt | list[NonNegativeInt] = Field(default=1)
55
- """Number of triggers that will be sent, (0 means infinite).
54
+ number_of_events: NonNegativeInt | list[NonNegativeInt] = Field(default=1)
55
+ """Number of events that will be processed, (0 means infinite).
56
56
 
57
57
  Can be:
58
58
  - A single integer or
59
- - A list of integers for multiple triggers
59
+ - A list of integers for multiple events
60
60
 
61
- Example for tomography: ``TriggerInfo(number=[2,3,100,3])``.
62
- This would trigger:
61
+ Example for tomography: ``TriggerInfo(number_of_events=[2,3,100,3])``.
62
+ This would process:
63
63
 
64
- - 2 times for dark field images
65
- - 3 times for initial flat field images
66
- - 100 times for projections
67
- - 3 times for final flat field images
64
+ - 2 events for dark field images
65
+ - 3 events for initial flat field images
66
+ - 100 events for projections
67
+ - 3 events for final flat field images
68
68
  """
69
69
 
70
70
  trigger: DetectorTrigger = Field(default=DetectorTrigger.INTERNAL)
71
71
  """Sort of triggers that will be sent"""
72
72
 
73
73
  deadtime: float = Field(default=0.0, ge=0)
74
- """What is the minimum deadtime between triggers"""
74
+ """What is the minimum deadtime between exposures"""
75
75
 
76
76
  livetime: float | None = Field(default=None, ge=0)
77
- """What is the maximum high time of the triggers"""
78
-
79
- frame_timeout: float | None = Field(default=None, gt=0)
80
- """What is the maximum timeout on waiting for a frame"""
81
-
82
- multiplier: int = 1
83
- """How many triggers make up a single StreamDatum index, to allow multiple frames
84
- from a faster detector to be zipped with a single frame from a slow detector
85
- e.g. if num=10 and multiplier=5 then the detector will take 10 frames,
86
- but publish 2 indices, and describe() will show a shape of (5, h, w)
77
+ """What is the maximum high time of the exposures"""
78
+
79
+ exposure_timeout: float | None = Field(default=None, gt=0)
80
+ """What is the maximum timeout on waiting for an exposure"""
81
+
82
+ exposures_per_event: PositiveInt = 1
83
+ """The number of exposures that are grouped into a single StreamDatum index.
84
+ A exposures_per_event > 1 can be useful to have exposures from a faster detector
85
+ able to be zipped with a single exposure from a slower detector. E.g. if
86
+ number_of_events=10 and exposures_per_event=5 then the detector will take
87
+ 10 exposures, but publish 2 StreamDatum indices, and describe() will show a
88
+ shape of (5, h, w) for each.
89
+ Default is 1.
87
90
  """
88
91
 
89
92
  @computed_field
90
93
  @cached_property
91
- def total_number_of_triggers(self) -> int:
94
+ def total_number_of_exposures(self) -> int:
92
95
  return (
93
- sum(self.number_of_triggers)
94
- if isinstance(self.number_of_triggers, list)
95
- else self.number_of_triggers
96
- )
96
+ sum(self.number_of_events)
97
+ if isinstance(self.number_of_events, list)
98
+ else self.number_of_events
99
+ ) * self.exposures_per_event
97
100
 
98
101
 
99
102
  class DetectorController(ABC):
@@ -127,16 +130,17 @@ class DetectorWriter(ABC):
127
130
  """Logic for making detector write data to somewhere persistent (e.g. HDF5 file)."""
128
131
 
129
132
  @abstractmethod
130
- async def open(self, multiplier: int = 1) -> dict[str, DataKey]:
133
+ async def open(
134
+ self, name: str, exposures_per_event: PositiveInt = 1
135
+ ) -> dict[str, DataKey]:
131
136
  """Open writer and wait for it to be ready for data.
132
137
 
133
- :param multiplier:
138
+ :param exposures_per_event:
134
139
  Each StreamDatum index corresponds to this many written exposures
135
140
  :return: Output for ``describe()``
136
141
  """
137
142
 
138
- @property
139
- def hints(self) -> Hints:
143
+ def get_hints(self, name: str) -> Hints:
140
144
  """The hints to be used for the detector."""
141
145
  return {}
142
146
 
@@ -153,7 +157,9 @@ class DetectorWriter(ABC):
153
157
  """Yield the index of each frame (or equivalent data point) as it is written."""
154
158
 
155
159
  @abstractmethod
156
- def collect_stream_docs(self, indices_written: int) -> AsyncIterator[StreamAsset]:
160
+ def collect_stream_docs(
161
+ self, name: str, indices_written: int
162
+ ) -> AsyncIterator[StreamAsset]:
157
163
  """Create Stream docs up to given number written."""
158
164
 
159
165
  @abstractmethod
@@ -215,11 +221,11 @@ class StandardDetector(
215
221
  self._watchers: list[Callable] = []
216
222
  self._fly_status: WatchableAsyncStatus | None = None
217
223
  self._fly_start: float | None = None
218
- self._frames_to_complete: int = 0
219
- # Represents the total number of frames that will have been completed at the
224
+ self._events_to_complete: int = 0
225
+ # Represents the total number of exposures that will have been completed at the
220
226
  # end of the next `complete`.
221
- self._completable_frames: int = 0
222
- self._number_of_triggers_iter: Iterator[int] | None = None
227
+ self._completable_exposures: int = 0
228
+ self._number_of_events_iter: Iterator[int] | None = None
223
229
  self._initial_frame: int = 0
224
230
  super().__init__(name, connector=connector)
225
231
 
@@ -269,15 +275,19 @@ class StandardDetector(
269
275
  if self._trigger_info is None:
270
276
  await self.prepare(
271
277
  TriggerInfo(
272
- number_of_triggers=1,
278
+ number_of_events=1,
273
279
  trigger=DetectorTrigger.INTERNAL,
274
280
  )
275
281
  )
276
-
277
282
  trigger_info = _ensure_trigger_info_exists(self._trigger_info)
278
283
  if trigger_info.trigger is not DetectorTrigger.INTERNAL:
279
284
  msg = "The trigger method can only be called with INTERNAL triggering"
280
285
  raise ValueError(msg)
286
+ if trigger_info.number_of_events != 1:
287
+ raise ValueError(
288
+ "Triggering is not supported for multiple events, the detector was "
289
+ f"prepared with number_of_events={trigger_info.number_of_events}."
290
+ )
281
291
 
282
292
  # Arm the detector and wait for it to finish.
283
293
  indices_written = await self._writer.get_indices_written()
@@ -312,13 +322,15 @@ class StandardDetector(
312
322
  raise ValueError(msg)
313
323
  elif not value.deadtime:
314
324
  value.deadtime = self._controller.get_deadtime(value.livetime)
315
- self._number_of_triggers_iter = iter(
316
- value.number_of_triggers
317
- if isinstance(value.number_of_triggers, list)
318
- else [value.number_of_triggers]
325
+ self._trigger_info = value
326
+ self._number_of_events_iter = iter(
327
+ value.number_of_events
328
+ if isinstance(value.number_of_events, list)
329
+ else [value.number_of_events]
319
330
  )
320
331
  self._describe, _ = await asyncio.gather(
321
- self._writer.open(value.multiplier), self._controller.prepare(value)
332
+ self._writer.open(self.name, value.exposures_per_event),
333
+ self._controller.prepare(value),
322
334
  )
323
335
  self._initial_frame = await self._writer.get_indices_written()
324
336
  if value.trigger != DetectorTrigger.INTERNAL:
@@ -327,25 +339,27 @@ class StandardDetector(
327
339
 
328
340
  @AsyncStatus.wrap
329
341
  async def kickoff(self):
330
- if self._trigger_info is None or self._number_of_triggers_iter is None:
342
+ if self._trigger_info is None or self._number_of_events_iter is None:
331
343
  raise RuntimeError("Prepare must be called before kickoff!")
332
344
  if self._trigger_info.trigger == DetectorTrigger.INTERNAL:
333
345
  await self._controller.arm()
334
346
  self._fly_start = time.monotonic()
335
347
  try:
336
- self._frames_to_complete = next(self._number_of_triggers_iter)
337
- self._completable_frames += self._frames_to_complete
348
+ self._events_to_complete = next(self._number_of_events_iter)
349
+ self._completable_exposures += (
350
+ self._events_to_complete * self._trigger_info.exposures_per_event
351
+ )
338
352
  except StopIteration as err:
339
353
  raise RuntimeError(
340
354
  f"Kickoff called more than the configured number of "
341
- f"{self._trigger_info.total_number_of_triggers} iteration(s)!"
355
+ f"{self._trigger_info.total_number_of_exposures} iteration(s)!"
342
356
  ) from err
343
357
 
344
358
  @WatchableAsyncStatus.wrap
345
359
  async def complete(self):
346
360
  trigger_info = _ensure_trigger_info_exists(self._trigger_info)
347
361
  indices_written = self._writer.observe_indices_written(
348
- trigger_info.frame_timeout
362
+ trigger_info.exposure_timeout
349
363
  or (
350
364
  DEFAULT_TIMEOUT
351
365
  + (trigger_info.livetime or 0)
@@ -358,21 +372,21 @@ class StandardDetector(
358
372
  name=self.name,
359
373
  current=index,
360
374
  initial=self._initial_frame,
361
- target=self._frames_to_complete,
375
+ target=self._events_to_complete,
362
376
  unit="",
363
377
  precision=0,
364
378
  time_elapsed=time.monotonic() - self._fly_start
365
379
  if self._fly_start
366
380
  else None,
367
381
  )
368
- if index >= self._frames_to_complete:
382
+ if index >= self._events_to_complete:
369
383
  break
370
384
  finally:
371
385
  await indices_written.aclose()
372
- if self._completable_frames >= trigger_info.total_number_of_triggers:
373
- self._completable_frames = 0
374
- self._frames_to_complete = 0
375
- self._number_of_triggers_iter = None
386
+ if self._completable_exposures >= trigger_info.total_number_of_exposures:
387
+ self._completable_exposures = 0
388
+ self._events_to_complete = 0
389
+ self._number_of_events_iter = None
376
390
  await self._controller.wait_for_idle()
377
391
 
378
392
  async def describe_collect(self) -> dict[str, DataKey]:
@@ -386,7 +400,7 @@ class StandardDetector(
386
400
  # retrieved for step scans.
387
401
  if index is None:
388
402
  index = await self._writer.get_indices_written()
389
- async for doc in self._writer.collect_stream_docs(index):
403
+ async for doc in self._writer.collect_stream_docs(self.name, index):
390
404
  yield doc
391
405
 
392
406
  async def get_index(self) -> int:
@@ -394,4 +408,4 @@ class StandardDetector(
394
408
 
395
409
  @property
396
410
  def hints(self) -> Hints:
397
- return self._writer.hints
411
+ return self._writer.get_hints(self.name)
@@ -346,10 +346,10 @@ class DeviceProcessor:
346
346
 
347
347
 
348
348
  def init_devices(
349
- set_name=True,
349
+ set_name: bool = True,
350
350
  child_name_separator: str = "-",
351
- connect=True,
352
- mock=False,
351
+ connect: bool = True,
352
+ mock: bool = False,
353
353
  timeout: float = 10.0,
354
354
  ):
355
355
  """Auto initialize top level Device instances: to be used as a context manager.
@@ -2,7 +2,7 @@ from collections.abc import Iterator
2
2
  from pathlib import Path
3
3
  from urllib.parse import urlunparse
4
4
 
5
- from event_model import (
5
+ from event_model import ( # type: ignore
6
6
  ComposeStreamResource,
7
7
  ComposeStreamResourceBundle,
8
8
  StreamDatum,
@@ -34,9 +34,6 @@ class HDFDatasetDescription(BaseModel):
34
34
  chunk_shape: tuple[int, ...]
35
35
  """The explicit chunk size written to disk"""
36
36
 
37
- multiplier: int = 1
38
- """Won't be used soon."""
39
-
40
37
 
41
38
  SLICE_NAME = "AD_HDF5_SWMR_SLICE"
42
39
 
@@ -74,7 +71,6 @@ class HDFDocumentComposer:
74
71
  data_key=ds.data_key,
75
72
  parameters={
76
73
  "dataset": ds.dataset,
77
- "multiplier": ds.multiplier,
78
74
  "chunk_shape": ds.chunk_shape,
79
75
  },
80
76
  uid=None,
@@ -220,14 +220,6 @@ class YMDPathProvider(PathProvider):
220
220
  )
221
221
 
222
222
 
223
- class NameProvider(Protocol):
224
- """Base class for callable classes providing data keys."""
225
-
226
- @abstractmethod
227
- def __call__(self) -> str:
228
- """Get the name to be used as a data_key in the descriptor document."""
229
-
230
-
231
223
  class DatasetDescriber(Protocol):
232
224
  """For describing datasets in file writing."""
233
225
 
@@ -179,8 +179,20 @@ class StandardReadable(
179
179
 
180
180
  yield
181
181
 
182
- # Set symmetric difference operator gives all newly added keys
182
+ # Set symmetric difference operator gives all newly added keys.
183
183
  new_dict = dict(self.children())
184
+ for key, value in new_dict.items():
185
+ # Check if key already exists in dict_copy and if the value has changed.
186
+ if key in dict_copy and value != dict_copy[key]:
187
+ error_msg = (
188
+ f"Duplicate readable device found: '{key}' in {value.parent}. "
189
+ "Derived class must not redefine a readable. "
190
+ "See: https://github.com/bluesky/ophyd-async/issues/848. "
191
+ "If this functionality is required, please raise an issue: "
192
+ "https://github.com/bluesky/ophyd-async"
193
+ )
194
+ raise KeyError(error_msg)
195
+
184
196
  new_keys = dict_copy.keys() ^ new_dict.keys()
185
197
  new_values = [new_dict[key] for key in new_keys]
186
198
 
@@ -93,18 +93,19 @@ class Table(BaseModel):
93
93
 
94
94
  def __add__(self, right: TableSubclass) -> TableSubclass:
95
95
  """Concatenate the arrays in field values."""
96
- if type(right) is not type(self):
96
+ cls = type(right)
97
+ if type(self) is not cls:
97
98
  raise RuntimeError(
98
99
  f"{right} is not a `Table`, or is not the same "
99
100
  f"type of `Table` as {self}."
100
101
  )
101
102
 
102
- return type(right)(
103
+ return cls(
103
104
  **{
104
105
  field_name: _concat(
105
106
  getattr(self, field_name), getattr(right, field_name)
106
107
  )
107
- for field_name in self.model_fields
108
+ for field_name in cls.model_fields
108
109
  }
109
110
  )
110
111
 
@@ -32,7 +32,7 @@ class Andor2Controller(adcore.ADBaseController[Andor2DriverIO]):
32
32
  await asyncio.gather(
33
33
  self.driver.trigger_mode.set(self._get_trigger_mode(trigger_info.trigger)),
34
34
  self.driver.num_images.set(
35
- trigger_info.total_number_of_triggers or _MAX_NUM_IMAGE
35
+ trigger_info.total_number_of_exposures or _MAX_NUM_IMAGE
36
36
  ),
37
37
  self.driver.image_mode.set(adcore.ADImageMode.MULTIPLE),
38
38
  )
@@ -35,11 +35,11 @@ class AravisController(adcore.ADBaseController[AravisDriverIO]):
35
35
  else:
36
36
  raise ValueError(f"ADAravis does not support {trigger_info.trigger}")
37
37
 
38
- if trigger_info.total_number_of_triggers == 0:
38
+ if trigger_info.total_number_of_exposures == 0:
39
39
  image_mode = adcore.ADImageMode.CONTINUOUS
40
40
  else:
41
41
  image_mode = adcore.ADImageMode.MULTIPLE
42
42
  await asyncio.gather(
43
- self.driver.num_images.set(trigger_info.total_number_of_triggers),
43
+ self.driver.num_images.set(trigger_info.total_number_of_exposures),
44
44
  self.driver.image_mode.set(image_mode),
45
45
  )
@@ -33,7 +33,7 @@ class ADBaseController(DetectorController, Generic[ADBaseIOT]):
33
33
  driver: ADBaseIOT,
34
34
  good_states: frozenset[ADState] = DEFAULT_GOOD_STATES,
35
35
  ) -> None:
36
- self.driver = driver
36
+ self.driver: ADBaseIOT = driver
37
37
  self.good_states = good_states
38
38
  self.frame_timeout = DEFAULT_TIMEOUT
39
39
  self._arm_status: AsyncStatus | None = None
@@ -49,7 +49,7 @@ class ADBaseController(DetectorController, Generic[ADBaseIOT]):
49
49
  DEFAULT_TIMEOUT + await self.driver.acquire_time.get_value()
50
50
  )
51
51
  await asyncio.gather(
52
- self.driver.num_images.set(trigger_info.total_number_of_triggers),
52
+ self.driver.num_images.set(trigger_info.total_number_of_exposures),
53
53
  self.driver.image_mode.set(ADImageMode.MULTIPLE),
54
54
  )
55
55
 
@@ -176,7 +176,7 @@ class ADBaseContAcqController(ADBaseController[ADBaseIO]):
176
176
  await asyncio.gather(
177
177
  self.cb_plugin.enable_callbacks.set(ADCallbacks.ENABLE),
178
178
  self.cb_plugin.pre_count.set(0),
179
- self.cb_plugin.post_count.set(trigger_info.total_number_of_triggers),
179
+ self.cb_plugin.post_count.set(trigger_info.total_number_of_exposures),
180
180
  self.cb_plugin.preset_trigger_count.set(1),
181
181
  self.cb_plugin.flush_on_soft_trg.set(NDCBFlushOnSoftTrgMode.ON_NEW_IMAGE),
182
182
  )
@@ -5,14 +5,15 @@ from typing import Generic, TypeVar, get_args
5
5
  from urllib.parse import urlunparse
6
6
 
7
7
  from bluesky.protocols import Hints, StreamAsset
8
- from event_model import (
8
+ from event_model import ( # type: ignore
9
9
  ComposeStreamResource,
10
10
  DataKey,
11
11
  StreamRange,
12
12
  )
13
+ from pydantic import PositiveInt
13
14
 
14
15
  from ophyd_async.core._detector import DetectorWriter
15
- from ophyd_async.core._providers import DatasetDescriber, NameProvider, PathProvider
16
+ from ophyd_async.core._providers import DatasetDescriber, PathProvider
16
17
  from ophyd_async.core._signal import (
17
18
  observe_value,
18
19
  set_and_wait_for_value,
@@ -44,7 +45,6 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
44
45
  self,
45
46
  fileio: NDFileIOT,
46
47
  path_provider: PathProvider,
47
- name_provider: NameProvider,
48
48
  dataset_describer: DatasetDescriber,
49
49
  file_extension: str = "",
50
50
  mimetype: str = "",
@@ -53,7 +53,6 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
53
53
  self._plugins = plugins or {}
54
54
  self.fileio = fileio
55
55
  self._path_provider = path_provider
56
- self._name_provider = name_provider
57
56
  self._dataset_describer = dataset_describer
58
57
  self._file_extension = file_extension
59
58
  self._mimetype = mimetype
@@ -61,7 +60,6 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
61
60
  self._emitted_resource = None
62
61
 
63
62
  self._capture_status: AsyncStatus | None = None
64
- self._multiplier = 1
65
63
  self._filename_template = "%s%s_%6.6d"
66
64
 
67
65
  @classmethod
@@ -81,18 +79,11 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
81
79
  fileio = fileio_cls(prefix + (fileio_suffix or cls.default_suffix))
82
80
  dataset_describer = ADBaseDatasetDescriber(dataset_source or fileio)
83
81
 
84
- def name_provider() -> str:
85
- if fileio.parent == "Not attached to a detector":
86
- raise RuntimeError("Initializing writer without parent detector!")
87
- return fileio.parent.name
88
-
89
- writer = cls(
90
- fileio, path_provider, name_provider, dataset_describer, plugins=plugins
91
- )
82
+ writer = cls(fileio, path_provider, dataset_describer, plugins=plugins)
92
83
  return writer
93
84
 
94
- async def begin_capture(self) -> None:
95
- info = self._path_provider(device_name=self._name_provider())
85
+ async def begin_capture(self, name: str) -> None:
86
+ info = self._path_provider(device_name=name)
96
87
 
97
88
  await self.fileio.enable_callbacks.set(ADCallbacks.ENABLE)
98
89
 
@@ -125,19 +116,21 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
125
116
  self.fileio.capture, True, wait_for_set_completion=False
126
117
  )
127
118
 
128
- async def open(self, multiplier: int = 1) -> dict[str, DataKey]:
119
+ async def open(
120
+ self, name: str, exposures_per_event: PositiveInt = 1
121
+ ) -> dict[str, DataKey]:
129
122
  self._emitted_resource = None
130
123
  self._last_emitted = 0
131
- self._multiplier = multiplier
124
+ self._exposures_per_event = exposures_per_event
132
125
  frame_shape = await self._dataset_describer.shape()
133
126
  dtype_numpy = await self._dataset_describer.np_datatype()
134
127
 
135
- await self.begin_capture()
128
+ await self.begin_capture(name)
136
129
 
137
130
  describe = {
138
- self._name_provider(): DataKey(
131
+ name: DataKey(
139
132
  source=self.fileio.full_file_name.source,
140
- shape=list(frame_shape),
133
+ shape=[exposures_per_event, *frame_shape],
141
134
  dtype="array",
142
135
  dtype_numpy=dtype_numpy,
143
136
  external="STREAM:",
@@ -150,14 +143,14 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
150
143
  ) -> AsyncGenerator[int, None]:
151
144
  """Wait until a specific index is ready to be collected."""
152
145
  async for num_captured in observe_value(self.fileio.num_captured, timeout):
153
- yield num_captured // self._multiplier
146
+ yield num_captured // self._exposures_per_event
154
147
 
155
148
  async def get_indices_written(self) -> int:
156
149
  num_captured = await self.fileio.num_captured.get_value()
157
- return num_captured // self._multiplier
150
+ return num_captured // self._exposures_per_event
158
151
 
159
152
  async def collect_stream_docs(
160
- self, indices_written: int
153
+ self, name: str, indices_written: int
161
154
  ) -> AsyncIterator[StreamAsset]:
162
155
  if indices_written:
163
156
  if not self._emitted_resource:
@@ -183,13 +176,14 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
183
176
  self._emitted_resource = bundler_composer(
184
177
  mimetype=self._mimetype,
185
178
  uri=uri,
186
- data_key=self._name_provider(),
179
+ # TODO no reference to detector's name
180
+ data_key=name,
187
181
  parameters={
188
- # Assume that we always write 1 frame per file/chunk
182
+ # Assume that we always write 1 frame per file/chunk, this
183
+ # may change to self._exposures_per_event in the future
189
184
  "chunk_shape": (1, *frame_shape),
190
185
  # Include file template for reconstruction in consolidator
191
186
  "template": file_template,
192
- "multiplier": self._multiplier,
193
187
  },
194
188
  uid=None,
195
189
  validate=True,
@@ -218,6 +212,5 @@ class ADWriter(DetectorWriter, Generic[NDFileIOT]):
218
212
  await self._capture_status
219
213
  self._capture_status = None
220
214
 
221
- @property
222
- def hints(self) -> Hints:
223
- return {"fields": [self._name_provider()]}
215
+ def get_hints(self, name: str) -> Hints:
216
+ return {"fields": [name]}