ophyd-async 0.3a6__tar.gz → 0.3.1a1__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 (199) hide show
  1. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/PKG-INFO +2 -2
  2. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/README.md +1 -1
  3. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/write-tests-for-devices.rst +5 -0
  4. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/_version.py +2 -2
  5. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/__init__.py +3 -5
  6. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/detector.py +15 -10
  7. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/mock_signal_backend.py +5 -8
  8. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/mock_signal_utils.py +25 -11
  9. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/signal_backend.py +1 -1
  10. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/standard_readable.py +2 -0
  11. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +18 -5
  12. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +2 -2
  13. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/pilatus.py +21 -4
  14. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_hdf_panda.py +0 -1
  15. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/plan_stubs/fly.py +4 -0
  16. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/sim_pattern_generator.py +0 -2
  17. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/PKG-INFO +2 -2
  18. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_flyer.py +0 -2
  19. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_mock_signal_backend.py +32 -27
  20. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_standard_readable.py +12 -1
  21. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_controllers.py +26 -16
  22. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_pilatus.py +48 -6
  23. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_scans.py +5 -3
  24. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/demo/test_demo.py +24 -0
  25. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/plan_stubs/test_fly.py +45 -5
  26. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.codecov.yml +0 -0
  27. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.copier-answers.yml +0 -0
  28. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.devcontainer/devcontainer.json +0 -0
  29. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.git-blame-ignore-revs +0 -0
  30. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/CONTRIBUTING.md +0 -0
  31. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/actions/install_requirements/action.yml +0 -0
  32. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/dependabot.yml +0 -0
  33. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/pages/index.html +0 -0
  34. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/pages/make_switcher.py +0 -0
  35. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_check.yml +0 -0
  36. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_dist.yml +0 -0
  37. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_docs.yml +0 -0
  38. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_pypi.yml +0 -0
  39. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_release.yml +0 -0
  40. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_test.yml +0 -0
  41. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/_tox.yml +0 -0
  42. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/ci.yml +0 -0
  43. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.github/workflows/periodic.yml +0 -0
  44. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.gitignore +0 -0
  45. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.mailmap +0 -0
  46. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/.pre-commit-config.yaml +0 -0
  47. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/Dockerfile +0 -0
  48. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/LICENSE +0 -0
  49. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/_templates/README +0 -0
  50. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/_templates/custom-class-template.rst +0 -0
  51. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/_templates/custom-module-template.rst +0 -0
  52. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/conf.py +0 -0
  53. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/examples/epics_demo.py +0 -0
  54. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/examples/foo_detector.py +0 -0
  55. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  56. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  57. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  58. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  59. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  60. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  61. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions/COPYME +0 -0
  62. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/decisions.md +0 -0
  63. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/design-goals.rst +0 -0
  64. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/event-loop-choice.rst +0 -0
  65. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations/flyscanning.rst +0 -0
  66. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/explanations.md +0 -0
  67. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/genindex.rst +0 -0
  68. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/choose-interfaces-for-devices.md +0 -0
  69. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/compound-devices.rst +0 -0
  70. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/contribute.md +0 -0
  71. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/make-a-simple-device.rst +0 -0
  72. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to/make-a-standard-detector.rst +0 -0
  73. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/how-to.md +0 -0
  74. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
  75. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/images/bluesky_ophyd_logo.svg +0 -0
  76. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/images/ophyd_favicon.svg +0 -0
  77. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/index.md +0 -0
  78. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/reference/api.rst +0 -0
  79. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/reference.md +0 -0
  80. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/tutorials/installation.md +0 -0
  81. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/tutorials/using-existing-devices.rst +0 -0
  82. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/docs/tutorials.md +0 -0
  83. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/pyproject.toml +0 -0
  84. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/setup.cfg +0 -0
  85. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/__init__.py +0 -0
  86. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/__main__.py +0 -0
  87. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/_providers.py +0 -0
  88. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/async_status.py +0 -0
  89. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/device.py +0 -0
  90. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/device_save_loader.py +0 -0
  91. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/flyer.py +0 -0
  92. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/signal.py +0 -0
  93. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/soft_signal_backend.py +0 -0
  94. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/core/utils.py +0 -0
  95. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/__init__.py +0 -0
  96. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/_backend/__init__.py +0 -0
  97. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/_backend/_aioca.py +0 -0
  98. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/_backend/_p4p.py +0 -0
  99. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/_backend/common.py +0 -0
  100. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/__init__.py +0 -0
  101. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/aravis.py +0 -0
  102. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
  103. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
  104. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +0 -0
  105. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
  106. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
  107. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/__init__.py +0 -0
  108. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +0 -0
  109. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +0 -0
  110. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +0 -0
  111. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +0 -0
  112. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
  113. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
  114. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/utils.py +0 -0
  115. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
  116. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
  117. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
  118. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
  119. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +0 -0
  120. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -0
  121. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +0 -0
  122. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/demo/__init__.py +0 -0
  123. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
  124. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/demo/mover.db +0 -0
  125. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/demo/sensor.db +0 -0
  126. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/motion/__init__.py +0 -0
  127. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/motion/motor.py +0 -0
  128. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/pvi/__init__.py +0 -0
  129. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/pvi/pvi.py +0 -0
  130. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/signal/__init__.py +0 -0
  131. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
  132. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/epics/signal/signal.py +0 -0
  133. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/log.py +0 -0
  134. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/__init__.py +0 -0
  135. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_common_blocks.py +0 -0
  136. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_panda_controller.py +0 -0
  137. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_table.py +0 -0
  138. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_trigger.py +0 -0
  139. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/_utils.py +0 -0
  140. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/writers/__init__.py +0 -0
  141. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/writers/_hdf_writer.py +0 -0
  142. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/panda/writers/_panda_hdf_file.py +0 -0
  143. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  144. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/plan_stubs/ensure_connected.py +0 -0
  145. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/protocols.py +0 -0
  146. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/__init__.py +0 -0
  147. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/demo/__init__.py +0 -0
  148. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/demo/sim_motor.py +0 -0
  149. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/pattern_generator.py +0 -0
  150. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
  151. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
  152. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/SOURCES.txt +0 -0
  153. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  154. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/entry_points.txt +0 -0
  155. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/requires.txt +0 -0
  156. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/src/ophyd_async.egg-info/top_level.txt +0 -0
  157. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/conftest.py +0 -0
  158. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_async_status.py +0 -0
  159. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_device.py +0 -0
  160. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_device_collector.py +0 -0
  161. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_device_save_loader.py +0 -0
  162. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_signal.py +0 -0
  163. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_soft_signal_backend.py +0 -0
  164. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_utils.py +0 -0
  165. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/core/test_watchable_async_status.py +0 -0
  166. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/_backend/test_common.py +0 -0
  167. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/__init__.py +0 -0
  168. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_aravis.py +0 -0
  169. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_drivers.py +0 -0
  170. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_kinetix.py +0 -0
  171. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_single_trigger_det.py +0 -0
  172. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_utils.py +0 -0
  173. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_vimba.py +0 -0
  174. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/areadetector/test_writers.py +0 -0
  175. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/demo/test_demo_ad_sim_detector.py +0 -0
  176. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/motion/__init__.py +0 -0
  177. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/motion/test_motor.py +0 -0
  178. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/test_pvi.py +0 -0
  179. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/test_records.db +0 -0
  180. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/epics/test_signals.py +0 -0
  181. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/db/panda.db +0 -0
  182. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_hdf_panda.py +0 -0
  183. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_panda_connect.py +0 -0
  184. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_panda_controller.py +0 -0
  185. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_panda_utils.py +0 -0
  186. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_table.py +0 -0
  187. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_trigger.py +0 -0
  188. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/panda/test_writer.py +0 -0
  189. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/protocols/test_protocols.py +0 -0
  190. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/__init__.py +0 -0
  191. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/conftest.py +0 -0
  192. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/demo/__init__.py +0 -0
  193. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/demo/test_sim_motor.py +0 -0
  194. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/test_pattern_generator.py +0 -0
  195. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/test_sim_detector.py +0 -0
  196. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/test_sim_writer.py +0 -0
  197. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/sim/test_streaming_plan.py +0 -0
  198. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/test_cli.py +0 -0
  199. {ophyd_async-0.3a6 → ophyd_async-0.3.1a1}/tests/test_log.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3a6
3
+ Version: 0.3.1a1
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
@@ -96,7 +96,7 @@ Requires-Dist: types-pyyaml; extra == "dev"
96
96
 
97
97
  # ophyd-async
98
98
 
99
- Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
99
+ Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango.
100
100
 
101
101
  | Source | <https://github.com/bluesky/ophyd-async> |
102
102
  | :-----------: | :-----------------------------------------------: |
@@ -5,7 +5,7 @@
5
5
 
6
6
  # ophyd-async
7
7
 
8
- Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
8
+ Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango.
9
9
 
10
10
  | Source | <https://github.com/bluesky/ophyd-async> |
11
11
  | :-----------: | :-----------------------------------------------: |
@@ -41,6 +41,11 @@ In addition this example also utilizes helper functions like ``assert_reading``
41
41
  :pyobject: test_sensor_reading_shows_value
42
42
 
43
43
 
44
+ Given that the mock signal holds a ``unittest.mock.Mock`` object you can retrieve this object and assert that the device has been set correctly using ``get_mock_put``. You are also free to use any other behaviour that ``unittest.mock.Mock`` provides, such as in this example which sets the parent of the mock to allow ordering across signals to be asserted:
45
+
46
+ .. literalinclude:: ../../tests/epics/demo/test_demo.py
47
+ :pyobject: test_retrieve_mock_and_assert
48
+
44
49
  There are several other test utility functions:
45
50
 
46
51
  Use ``callback_on_mock_put``, for hooking in logic when a mock value changes (e.g. because someone puts to it). This can be called directly, or used as a context, with the callbacks ending after exit.
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.3a6'
16
- __version_tuple__ = version_tuple = (0, 3)
15
+ __version__ = version = '0.3.1a1'
16
+ __version_tuple__ = version_tuple = (0, 3, 1)
@@ -24,12 +24,10 @@ from .device_save_loader import (
24
24
  walk_rw_signals,
25
25
  )
26
26
  from .flyer import HardwareTriggeredFlyable, TriggerLogic
27
- from .mock_signal_backend import (
28
- MockSignalBackend,
29
- )
27
+ from .mock_signal_backend import MockSignalBackend
30
28
  from .mock_signal_utils import (
31
- assert_mock_put_called_with,
32
29
  callback_on_mock_put,
30
+ get_mock_put,
33
31
  mock_puts_blocked,
34
32
  reset_mock_put_calls,
35
33
  set_mock_put_proceeds,
@@ -70,7 +68,7 @@ from .utils import (
70
68
  )
71
69
 
72
70
  __all__ = [
73
- "assert_mock_put_called_with",
71
+ "get_mock_put",
74
72
  "callback_on_mock_put",
75
73
  "mock_puts_blocked",
76
74
  "set_mock_values",
@@ -63,6 +63,8 @@ class TriggerInfo:
63
63
  deadtime: float
64
64
  #: What is the maximum high time of the triggers
65
65
  livetime: float
66
+ #: What is the maximum timeout on waiting for a frame
67
+ frame_timeout: float | None = None
66
68
 
67
69
 
68
70
  class DetectorControl(ABC):
@@ -162,7 +164,6 @@ class StandardDetector(
162
164
  writer: DetectorWriter,
163
165
  config_sigs: Sequence[AsyncReadable] = (),
164
166
  name: str = "",
165
- writer_timeout: float = DEFAULT_TIMEOUT,
166
167
  ) -> None:
167
168
  """
168
169
  Constructor
@@ -173,16 +174,11 @@ class StandardDetector(
173
174
  config_sigs: Signals to read when describe and read
174
175
  configuration are called. Defaults to ().
175
176
  name: Device name. Defaults to "".
176
- writer_timeout: Timeout for frame writing to start, if the
177
- timeout is reached, ophyd-async assumes the detector
178
- has a problem and raises an error.
179
- Defaults to DEFAULT_TIMEOUT.
180
177
  """
181
178
  self._controller = controller
182
179
  self._writer = writer
183
180
  self._describe: Dict[str, DataKey] = {}
184
181
  self._config_sigs = list(config_sigs)
185
- self._frame_writing_timeout = writer_timeout
186
182
  # For prepare
187
183
  self._arm_status: Optional[AsyncStatus] = None
188
184
  self._trigger_info: Optional[TriggerInfo] = None
@@ -245,17 +241,21 @@ class StandardDetector(
245
241
 
246
242
  @AsyncStatus.wrap
247
243
  async def trigger(self) -> None:
244
+ # set default trigger_info
245
+ self._trigger_info = TriggerInfo(
246
+ num=1, trigger=DetectorTrigger.internal, deadtime=0.0, livetime=0.0
247
+ )
248
248
  # Arm the detector and wait for it to finish.
249
249
  indices_written = await self.writer.get_indices_written()
250
250
  written_status = await self.controller.arm(
251
- num=1,
252
- trigger=DetectorTrigger.internal,
251
+ num=self._trigger_info.num,
252
+ trigger=self._trigger_info.trigger,
253
253
  )
254
254
  await written_status
255
255
  end_observation = indices_written + 1
256
256
 
257
257
  async for index in self.writer.observe_indices_written(
258
- self._frame_writing_timeout
258
+ DEFAULT_TIMEOUT + self._trigger_info.livetime + self._trigger_info.deadtime
259
259
  ):
260
260
  if index >= end_observation:
261
261
  break
@@ -309,7 +309,12 @@ class StandardDetector(
309
309
  assert self._arm_status, "Prepare not run"
310
310
  assert self._trigger_info
311
311
  async for index in self.writer.observe_indices_written(
312
- self._frame_writing_timeout
312
+ self._trigger_info.frame_timeout
313
+ or (
314
+ DEFAULT_TIMEOUT
315
+ + self._trigger_info.livetime
316
+ + self._trigger_info.deadtime
317
+ )
313
318
  ):
314
319
  yield WatcherUpdate(
315
320
  name=self.name,
@@ -1,6 +1,6 @@
1
1
  import asyncio
2
2
  from functools import cached_property
3
- from typing import Optional, Type
3
+ from typing import Callable, Optional, Type
4
4
  from unittest.mock import Mock
5
5
 
6
6
  from bluesky.protocols import Descriptor, Reading
@@ -10,7 +10,7 @@ from ophyd_async.core.soft_signal_backend import SoftSignalBackend
10
10
  from ophyd_async.core.utils import DEFAULT_TIMEOUT, ReadingValueCallback, T
11
11
 
12
12
 
13
- class MockSignalBackend(SignalBackend):
13
+ class MockSignalBackend(SignalBackend[T]):
14
14
  def __init__(
15
15
  self,
16
16
  datatype: Optional[Type[T]] = None,
@@ -31,11 +31,11 @@ class MockSignalBackend(SignalBackend):
31
31
 
32
32
  if not isinstance(self.initial_backend, SoftSignalBackend):
33
33
  # If the backend is a hard signal backend, or not provided,
34
- # then we create a soft signal to mimick it
34
+ # then we create a soft signal to mimic it
35
35
 
36
36
  self.soft_backend = SoftSignalBackend(datatype=datatype)
37
37
  else:
38
- self.soft_backend = initial_backend
38
+ self.soft_backend = self.initial_backend
39
39
 
40
40
  def source(self, name: str) -> str:
41
41
  if self.initial_backend:
@@ -47,7 +47,7 @@ class MockSignalBackend(SignalBackend):
47
47
 
48
48
  @cached_property
49
49
  def put_mock(self) -> Mock:
50
- return Mock(name="put")
50
+ return Mock(name="put", spec=Callable)
51
51
 
52
52
  @cached_property
53
53
  def put_proceeds(self) -> asyncio.Event:
@@ -65,9 +65,6 @@ class MockSignalBackend(SignalBackend):
65
65
  def set_value(self, value: T):
66
66
  self.soft_backend.set_value(value)
67
67
 
68
- async def get_descriptor(self, source: str) -> Descriptor:
69
- return await self.soft_backend.get_descriptor(source)
70
-
71
68
  async def get_reading(self) -> Reading:
72
69
  return await self.soft_backend.get_reading()
73
70
 
@@ -1,6 +1,6 @@
1
1
  from contextlib import asynccontextmanager, contextmanager
2
- from typing import Any, Callable, Iterable, Iterator, List
3
- from unittest.mock import ANY, Mock
2
+ from typing import Any, Callable, Iterable
3
+ from unittest.mock import Mock
4
4
 
5
5
  from ophyd_async.core.signal import Signal
6
6
  from ophyd_async.core.utils import T
@@ -22,7 +22,7 @@ def set_mock_value(signal: Signal[T], value: T):
22
22
  backend.set_value(value)
23
23
 
24
24
 
25
- def set_mock_put_proceeds(signal: Signal[T], proceeds: bool):
25
+ def set_mock_put_proceeds(signal: Signal, proceeds: bool):
26
26
  """Allow or block a put with wait=True from proceeding"""
27
27
  backend = _get_mock_signal_backend(signal)
28
28
 
@@ -33,7 +33,7 @@ def set_mock_put_proceeds(signal: Signal[T], proceeds: bool):
33
33
 
34
34
 
35
35
  @asynccontextmanager
36
- async def mock_puts_blocked(*signals: List[Signal]):
36
+ async def mock_puts_blocked(*signals: Signal):
37
37
  for signal in signals:
38
38
  set_mock_put_proceeds(signal, False)
39
39
  yield
@@ -41,9 +41,9 @@ async def mock_puts_blocked(*signals: List[Signal]):
41
41
  set_mock_put_proceeds(signal, True)
42
42
 
43
43
 
44
- def assert_mock_put_called_with(signal: Signal, value: Any, wait=ANY, timeout=ANY):
45
- backend = _get_mock_signal_backend(signal)
46
- backend.put_mock.assert_called_with(value, wait=wait, timeout=timeout)
44
+ def get_mock_put(signal: Signal) -> Mock:
45
+ """Get the mock associated with the put call on the signal."""
46
+ return _get_mock_signal_backend(signal).put_mock
47
47
 
48
48
 
49
49
  def reset_mock_put_calls(signal: Signal):
@@ -79,15 +79,29 @@ class _SetValuesIterator:
79
79
  return next_value
80
80
 
81
81
  def __del__(self):
82
- if self.require_all_consumed and self.index != len(self.values):
83
- raise AssertionError("Not all values have been consumed.")
82
+ if self.require_all_consumed:
83
+ # Values is cast to a list here because the user has supplied
84
+ # require_all_consumed=True, we can therefore assume they
85
+ # supplied a finite list.
86
+ # In the case of require_all_consumed=False, an infinite
87
+ # iterble is permitted
88
+ values = list(self.values)
89
+ if self.index != len(values):
90
+ # Report the values consumed and the values yet to be
91
+ # consumed
92
+ consumed = values[0 : self.index]
93
+ to_be_consumed = values[self.index :]
94
+ raise AssertionError(
95
+ f"{self.signal.name}: {consumed} were consumed "
96
+ f"but {to_be_consumed} were not consumed"
97
+ )
84
98
 
85
99
 
86
100
  def set_mock_values(
87
101
  signal: Signal,
88
102
  values: Iterable[Any],
89
103
  require_all_consumed: bool = False,
90
- ) -> Iterator[Any]:
104
+ ) -> _SetValuesIterator:
91
105
  """Iterator to set a signal to a sequence of values, optionally repeating the
92
106
  sequence.
93
107
 
@@ -127,7 +141,7 @@ def _unset_side_effect_cm(put_mock: Mock):
127
141
  put_mock.side_effect = None
128
142
 
129
143
 
130
- def callback_on_mock_put(signal: Signal, callback: Callable[[T], None]):
144
+ def callback_on_mock_put(signal: Signal[T], callback: Callable[[T], None]):
131
145
  """For setting a callback when a backend is put to.
132
146
 
133
147
  Can either be used in a context, with the callback being
@@ -14,7 +14,7 @@ class SignalBackend(Generic[T]):
14
14
 
15
15
  #: Like ca://PV_PREFIX:SIGNAL
16
16
  @abstractmethod
17
- def source(name: str) -> str:
17
+ def source(self, name: str) -> str:
18
18
  """Return source of signal. Signals may pass a name to the backend, which can be
19
19
  used or discarded."""
20
20
 
@@ -254,6 +254,8 @@ class HintedSignal(HasHints, AsyncReadable):
254
254
 
255
255
  @property
256
256
  def hints(self) -> Hints:
257
+ if self.signal.name == "":
258
+ return {"fields": []}
257
259
  return {"fields": [self.signal.name]}
258
260
 
259
261
  @classmethod
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  from typing import Optional
3
3
 
4
+ from ophyd_async.core import DEFAULT_TIMEOUT, wait_for_value
4
5
  from ophyd_async.core.async_status import AsyncStatus
5
6
  from ophyd_async.core.detector import DetectorControl, DetectorTrigger
6
7
  from ophyd_async.epics.areadetector.drivers.ad_base import (
@@ -23,14 +24,13 @@ class PilatusController(DetectorControl):
23
24
  def __init__(
24
25
  self,
25
26
  driver: PilatusDriver,
27
+ readout_time: float,
26
28
  ) -> None:
27
29
  self._drv = driver
30
+ self._readout_time = readout_time
28
31
 
29
32
  def get_deadtime(self, exposure: float) -> float:
30
- # Cite: https://media.dectris.com/User_Manual-PILATUS2-V1_4.pdf
31
- """The required minimum time difference between ExpPeriod and ExpTime
32
- (readout time) is 2.28 ms"""
33
- return 2.28e-3
33
+ return self._readout_time
34
34
 
35
35
  async def arm(
36
36
  self,
@@ -45,7 +45,20 @@ class PilatusController(DetectorControl):
45
45
  self._drv.num_images.set(999_999 if num == 0 else num),
46
46
  self._drv.image_mode.set(ImageMode.multiple),
47
47
  )
48
- return await start_acquiring_driver_and_ensure_status(self._drv)
48
+
49
+ # Standard arm the detector and wait for the acquire PV to be True
50
+ idle_status = await start_acquiring_driver_and_ensure_status(self._drv)
51
+
52
+ # The pilatus has an additional PV that goes True when the camserver
53
+ # is actually ready. Should wait for that too or we risk dropping
54
+ # a frame
55
+ await wait_for_value(
56
+ self._drv.armed_for_triggers,
57
+ True,
58
+ timeout=DEFAULT_TIMEOUT,
59
+ )
60
+
61
+ return idle_status
49
62
 
50
63
  @classmethod
51
64
  def _get_trigger_mode(cls, trigger: DetectorTrigger) -> PilatusTriggerMode:
@@ -1,7 +1,6 @@
1
1
  from enum import Enum
2
2
 
3
- from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
4
-
3
+ from ...signal import epics_signal_r, epics_signal_rw_rbv
5
4
  from .ad_base import ADBase
6
5
 
7
6
 
@@ -18,4 +17,5 @@ class PilatusDriver(ADBase):
18
17
  self.trigger_mode = epics_signal_rw_rbv(
19
18
  PilatusTriggerMode, prefix + "TriggerMode"
20
19
  )
20
+ self.armed_for_triggers = epics_signal_r(bool, prefix + "Armed")
21
21
  super().__init__(prefix, name)
@@ -1,3 +1,5 @@
1
+ from enum import Enum
2
+
1
3
  from bluesky.protocols import Hints
2
4
 
3
5
  from ophyd_async.core import DirectoryProvider
@@ -11,6 +13,20 @@ from ophyd_async.epics.areadetector.writers.hdf_writer import HDFWriter
11
13
  from ophyd_async.epics.areadetector.writers.nd_file_hdf import NDFileHDF
12
14
 
13
15
 
16
+ #: Cite: https://media.dectris.com/User_Manual-PILATUS2-V1_4.pdf
17
+ #: The required minimum time difference between ExpPeriod and ExpTime
18
+ #: (readout time) is 2.28 ms
19
+ #: We provide an option to override for newer Pilatus models
20
+ class PilatusReadoutTime(float, Enum):
21
+ """Pilatus readout time per model in ms"""
22
+
23
+ # Cite: https://media.dectris.com/User_Manual-PILATUS2-V1_4.pdf
24
+ pilatus2 = 2.28e-3
25
+
26
+ # Cite: https://media.dectris.com/user-manual-pilatus3-2020.pdf
27
+ pilatus3 = 0.95e-3
28
+
29
+
14
30
  class PilatusDetector(StandardDetector):
15
31
  """A Pilatus StandardDetector writing HDF files"""
16
32
 
@@ -21,15 +37,16 @@ class PilatusDetector(StandardDetector):
21
37
  self,
22
38
  prefix: str,
23
39
  directory_provider: DirectoryProvider,
24
- drv_suffix="cam1:",
25
- hdf_suffix="HDF1:",
26
- name="",
40
+ readout_time: PilatusReadoutTime = PilatusReadoutTime.pilatus3,
41
+ drv_suffix: str = "cam1:",
42
+ hdf_suffix: str = "HDF1:",
43
+ name: str = "",
27
44
  ):
28
45
  self.drv = PilatusDriver(prefix + drv_suffix)
29
46
  self.hdf = NDFileHDF(prefix + hdf_suffix)
30
47
 
31
48
  super().__init__(
32
- PilatusController(self.drv),
49
+ PilatusController(self.drv, readout_time=readout_time.value),
33
50
  HDFWriter(
34
51
  self.hdf,
35
52
  directory_provider,
@@ -38,7 +38,6 @@ class HDFPanda(CommonPandaBlocks, StandardDetector):
38
38
  writer=writer,
39
39
  config_sigs=config_sigs,
40
40
  name=name,
41
- writer_timeout=DEFAULT_TIMEOUT,
42
41
  )
43
42
 
44
43
  async def connect(
@@ -18,6 +18,7 @@ def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
18
18
  shutter_time: float,
19
19
  repeats: int = 1,
20
20
  period: float = 0.0,
21
+ frame_timeout: float | None = None,
21
22
  ):
22
23
  """Prepare a hardware triggered flyable and one or more detectors.
23
24
 
@@ -39,6 +40,7 @@ def prepare_static_seq_table_flyer_and_detectors_with_same_trigger(
39
40
  trigger=DetectorTrigger.constant_gate,
40
41
  deadtime=deadtime,
41
42
  livetime=exposure,
43
+ frame_timeout=frame_timeout,
42
44
  )
43
45
  trigger_time = number_of_frames * (exposure + deadtime)
44
46
  pre_delay = max(period - 2 * shutter_time - trigger_time, 0)
@@ -120,6 +122,7 @@ def time_resolved_fly_and_collect_with_static_seq_table(
120
122
  shutter_time: float,
121
123
  repeats: int = 1,
122
124
  period: float = 0.0,
125
+ frame_timeout: float | None = None,
123
126
  ):
124
127
  """Run a scan wth a flyer and multiple detectors.
125
128
 
@@ -144,6 +147,7 @@ def time_resolved_fly_and_collect_with_static_seq_table(
144
147
  shutter_time=shutter_time,
145
148
  repeats=repeats,
146
149
  period=period,
150
+ frame_timeout=frame_timeout,
147
151
  )
148
152
  # Run the fly scan
149
153
  yield from fly_and_collect(stream_name, flyer, detectors)
@@ -16,7 +16,6 @@ class SimPatternDetector(StandardDetector):
16
16
  path: Path,
17
17
  config_sigs: Sequence[AsyncReadable] = [],
18
18
  name: str = "sim_pattern_detector",
19
- writer_timeout: float = 1,
20
19
  ) -> None:
21
20
  self.directory_provider: DirectoryProvider = StaticDirectoryProvider(path)
22
21
  self.pattern_generator = PatternGenerator()
@@ -33,5 +32,4 @@ class SimPatternDetector(StandardDetector):
33
32
  writer=writer,
34
33
  config_sigs=config_sigs,
35
34
  name=name,
36
- writer_timeout=writer_timeout,
37
35
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3a6
3
+ Version: 0.3.1a1
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
@@ -96,7 +96,7 @@ Requires-Dist: types-pyyaml; extra == "dev"
96
96
 
97
97
  # ophyd-async
98
98
 
99
- Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango
99
+ Asynchronous Bluesky hardware abstraction code, compatible with control systems like EPICS and Tango.
100
100
 
101
101
  | Source | <https://github.com/bluesky/ophyd-async> |
102
102
  | :-----------: | :-----------------------------------------------: |
@@ -124,13 +124,11 @@ async def detectors(RE: RunEngine) -> tuple[StandardDetector, StandardDetector]:
124
124
  Mock(spec=DetectorControl, get_deadtime=lambda num: num, arm=dummy_arm_1),
125
125
  writers[0],
126
126
  name="detector_1",
127
- writer_timeout=3,
128
127
  )
129
128
  detector_2: StandardDetector[Any] = StandardDetector(
130
129
  Mock(spec=DetectorControl, get_deadtime=lambda num: num, arm=dummy_arm_2),
131
130
  writers[1],
132
131
  name="detector_2",
133
- writer_timeout=3,
134
132
  )
135
133
 
136
134
  return (detector_1, detector_2)
@@ -1,26 +1,22 @@
1
1
  import asyncio
2
2
  import re
3
3
  from itertools import repeat
4
- from unittest.mock import MagicMock, call
4
+ from unittest.mock import ANY, MagicMock, call
5
5
 
6
6
  import pytest
7
7
 
8
8
  from ophyd_async.core import MockSignalBackend, SignalRW
9
9
  from ophyd_async.core.device import Device, DeviceCollector
10
10
  from ophyd_async.core.mock_signal_utils import (
11
- assert_mock_put_called_with,
12
11
  callback_on_mock_put,
12
+ get_mock_put,
13
13
  mock_puts_blocked,
14
14
  reset_mock_put_calls,
15
15
  set_mock_put_proceeds,
16
16
  set_mock_value,
17
17
  set_mock_values,
18
18
  )
19
- from ophyd_async.core.signal import (
20
- SignalW,
21
- soft_signal_r_and_setter,
22
- soft_signal_rw,
23
- )
19
+ from ophyd_async.core.signal import SignalW, soft_signal_r_and_setter, soft_signal_rw
24
20
  from ophyd_async.core.soft_signal_backend import SoftSignalBackend
25
21
  from ophyd_async.epics.signal.signal import epics_signal_r, epics_signal_rw
26
22
 
@@ -31,6 +27,7 @@ async def test_mock_signal_backend(connect_mock_mode):
31
27
  # If mock is false it will be handled like a normal signal, otherwise it will
32
28
  # initalize a new backend from the one in the line above
33
29
  await mock_signal.connect(mock=connect_mock_mode)
30
+ assert isinstance(mock_signal._backend, MockSignalBackend)
34
31
 
35
32
  assert await mock_signal._backend.get_value() == ""
36
33
  await mock_signal._backend.put("test")
@@ -74,6 +71,8 @@ async def test_set_mock_put_proceeds():
74
71
  mock_signal = SignalW(SoftSignalBackend(str))
75
72
  await mock_signal.connect(mock=True)
76
73
 
74
+ assert isinstance(mock_signal._backend, MockSignalBackend)
75
+
77
76
  assert mock_signal._backend.put_proceeds.is_set() is True
78
77
 
79
78
  set_mock_put_proceeds(mock_signal, False)
@@ -95,6 +94,7 @@ async def test_set_mock_put_proceeds_timeout():
95
94
  async def test_put_proceeds_timeout():
96
95
  mock_signal = SignalW(SoftSignalBackend(str))
97
96
  await mock_signal.connect(mock=True)
97
+ assert isinstance(mock_signal._backend, MockSignalBackend)
98
98
 
99
99
  assert mock_signal._backend.put_proceeds.is_set() is True
100
100
 
@@ -112,14 +112,14 @@ async def test_mock_utils_throw_error_if_backend_isnt_mock_signal_backend():
112
112
  set_mock_value(signal, 10)
113
113
  exc_msgs.append(str(exc.value))
114
114
  with pytest.raises(AssertionError) as exc:
115
- assert_mock_put_called_with(signal, 10)
115
+ get_mock_put(signal).assert_called_once_with(10)
116
116
  exc_msgs.append(str(exc.value))
117
117
  with pytest.raises(AssertionError) as exc:
118
- async with mock_puts_blocked(signal, 10):
118
+ async with mock_puts_blocked(signal):
119
119
  ...
120
120
  exc_msgs.append(str(exc.value))
121
121
  with pytest.raises(AssertionError) as exc:
122
- with callback_on_mock_put(signal, 10):
122
+ with callback_on_mock_put(signal, lambda x: _):
123
123
  ...
124
124
  exc_msgs.append(str(exc.value))
125
125
  with pytest.raises(AssertionError) as exc:
@@ -137,16 +137,13 @@ async def test_mock_utils_throw_error_if_backend_isnt_mock_signal_backend():
137
137
  )
138
138
 
139
139
 
140
- async def test_assert_mock_put_called_with():
140
+ async def test_get_mock_put():
141
141
  mock_signal = epics_signal_rw(str, "READ_PV", "WRITE_PV", name="mock_name")
142
142
  await mock_signal.connect(mock=True)
143
143
  await mock_signal.set("test_value", wait=True, timeout=100)
144
144
 
145
- # can leave out kwargs
146
- assert_mock_put_called_with(mock_signal, "test_value")
147
- assert_mock_put_called_with(mock_signal, "test_value", wait=True)
148
- assert_mock_put_called_with(mock_signal, "test_value", timeout=100)
149
- assert_mock_put_called_with(mock_signal, "test_value", wait=True, timeout=100)
145
+ mock = get_mock_put(mock_signal)
146
+ mock.assert_called_once_with("test_value", wait=True, timeout=100)
150
147
 
151
148
  def err_text(text, wait, timeout):
152
149
  return (
@@ -162,7 +159,7 @@ async def test_assert_mock_put_called_with():
162
159
  ("test_value", False, 0), # wait and timeout wrong
163
160
  ]:
164
161
  with pytest.raises(AssertionError) as exc:
165
- assert_mock_put_called_with(mock_signal, text, wait=wait, timeout=timeout)
162
+ mock.assert_called_once_with(text, wait=wait, timeout=timeout)
166
163
  for err_substr in err_text(text, wait, timeout):
167
164
  assert err_substr in str(exc.value)
168
165
 
@@ -216,10 +213,8 @@ async def test_callback_on_mock_put_no_ctx():
216
213
  mock_signal = SignalRW(SoftSignalBackend(float))
217
214
  await mock_signal.connect(mock=True)
218
215
  calls = []
219
- (
220
- callback_on_mock_put(
221
- mock_signal, lambda *args, **kwargs: calls.append({**kwargs, "_args": args})
222
- ),
216
+ callback_on_mock_put(
217
+ mock_signal, lambda *args, **kwargs: calls.append({**kwargs, "_args": args})
223
218
  )
224
219
  await mock_signal.set(10.0)
225
220
  assert calls == [
@@ -249,16 +244,16 @@ async def test_callback_on_mock_put_fails_if_args_are_not_correct():
249
244
  async def test_set_mock_values(mock_signals):
250
245
  signal1, signal2 = mock_signals
251
246
 
252
- await signal2.get_value() == "first_value"
247
+ assert await signal2.get_value() == "first_value"
253
248
  for value_set in set_mock_values(signal1, ["second_value", "third_value"]):
254
249
  assert await signal1.get_value() == value_set
255
250
 
256
251
  iterator = set_mock_values(signal2, ["second_value", "third_value"])
257
- await signal2.get_value() == "first_value"
252
+ assert await signal2.get_value() == "first_value"
258
253
  next(iterator)
259
- await signal2.get_value() == "second_value"
254
+ assert await signal2.get_value() == "second_value"
260
255
  next(iterator)
261
- await signal2.get_value() == "third_value"
256
+ assert await signal2.get_value() == "third_value"
262
257
 
263
258
 
264
259
  async def test_set_mock_values_exhausted_passes(mock_signals):
@@ -300,10 +295,10 @@ async def test_set_mock_values_exhausted_fails(mock_signals):
300
295
  async def test_reset_mock_put_calls(mock_signals):
301
296
  signal1, signal2 = mock_signals
302
297
  await signal1.set("test_value", wait=True, timeout=1)
303
- assert_mock_put_called_with(signal1, "test_value")
298
+ get_mock_put(signal1).assert_called_with("test_value", wait=ANY, timeout=ANY)
304
299
  reset_mock_put_calls(signal1)
305
300
  with pytest.raises(AssertionError) as exc:
306
- assert_mock_put_called_with(signal1, "test_value")
301
+ get_mock_put(signal1).assert_called_with("test_value", wait=ANY, timeout=ANY)
307
302
  # Replacing spaces because they change between runners
308
303
  # (e.g the github actions runner has more)
309
304
  assert str(exc.value).replace(" ", "").replace("\n", "") == (
@@ -350,3 +345,13 @@ async def test_writing_to_soft_signals_in_mock():
350
345
  assert await signal.get_value() == 0
351
346
  backend_put(100)
352
347
  assert await signal.get_value() == 100
348
+
349
+
350
+ async def test_when_put_mock_called_with_typo_then_fails_but_calling_directly_passes():
351
+ mock_signal = SignalRW(SoftSignalBackend(int))
352
+ await mock_signal.connect(mock=True)
353
+ assert isinstance(mock_signal._backend, MockSignalBackend)
354
+ mock = mock_signal._backend.put_mock
355
+ with pytest.raises(AttributeError):
356
+ mock.asssert_called_once() # Note typo here is deliberate!
357
+ mock()