ophyd-async 0.3a3__tar.gz → 0.3a4__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 (204) hide show
  1. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/PKG-INFO +2 -2
  2. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/make-a-simple-device.rst +2 -1
  3. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/write-tests-for-devices.rst +10 -8
  4. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/tutorials/using-existing-devices.rst +1 -1
  5. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/pyproject.toml +1 -2
  6. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/_version.py +1 -1
  7. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/__init__.py +24 -10
  8. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/async_status.py +2 -0
  9. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/device.py +22 -9
  10. ophyd_async-0.3a4/src/ophyd_async/core/mock_signal_backend.py +86 -0
  11. ophyd_async-0.3a4/src/ophyd_async/core/mock_signal_utils.py +149 -0
  12. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/signal.py +38 -42
  13. ophyd_async-0.3a3/src/ophyd_async/core/sim_signal_backend.py → ophyd_async-0.3a4/src/ophyd_async/core/soft_signal_backend.py +23 -33
  14. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/_backend/_aioca.py +11 -7
  15. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/_backend/_p4p.py +11 -7
  16. ophyd_async-0.3a4/src/ophyd_async/epics/_backend/common.py +25 -0
  17. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/__init__.py +0 -4
  18. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +12 -10
  19. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +7 -5
  20. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +7 -4
  21. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +5 -2
  22. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +12 -7
  23. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/utils.py +2 -12
  24. ophyd_async-0.3a4/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +42 -0
  25. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +6 -7
  26. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/motion/motor.py +5 -1
  27. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/pvi/pvi.py +11 -11
  28. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_hdf_panda.py +3 -3
  29. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/demo/sim_motor.py +4 -4
  30. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/pattern_generator.py +5 -5
  31. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/PKG-INFO +2 -2
  32. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/SOURCES.txt +5 -2
  33. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/conftest.py +17 -0
  34. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_device.py +10 -3
  35. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_device_collector.py +18 -18
  36. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_device_save_loader.py +1 -1
  37. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_flyer.py +4 -5
  38. ophyd_async-0.3a4/tests/core/test_mock_signal_backend.py +341 -0
  39. ophyd_async-0.3a4/tests/core/test_signal.py +243 -0
  40. ophyd_async-0.3a3/tests/core/test_sim.py → ophyd_async-0.3a4/tests/core/test_soft_signal_backend.py +12 -17
  41. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_standard_readable.py +2 -2
  42. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_utils.py +24 -14
  43. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/_backend/test_common.py +12 -18
  44. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_aravis.py +20 -20
  45. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_controllers.py +2 -2
  46. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_drivers.py +5 -5
  47. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_kinetix.py +13 -13
  48. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_pilatus.py +3 -3
  49. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_scans.py +5 -5
  50. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_single_trigger_det.py +7 -7
  51. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_vimba.py +15 -15
  52. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_writers.py +4 -4
  53. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/demo/test_demo.py +98 -94
  54. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/demo/test_demo_ad_sim_detector.py +22 -22
  55. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/motion/test_motor.py +21 -19
  56. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/test_pvi.py +13 -9
  57. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/test_signals.py +35 -1
  58. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_hdf_panda.py +45 -78
  59. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_panda_connect.py +18 -16
  60. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_panda_controller.py +12 -11
  61. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_panda_utils.py +13 -11
  62. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_trigger.py +10 -8
  63. ophyd_async-0.3a4/tests/panda/test_writer.py +208 -0
  64. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/protocols/test_protocols.py +2 -9
  65. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/conftest.py +1 -1
  66. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/test_sim_detector.py +1 -1
  67. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/test_sim_writer.py +1 -1
  68. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/test_streaming_plan.py +0 -1
  69. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/test_flyer_with_panda.py +17 -15
  70. ophyd_async-0.3a3/src/ophyd_async/epics/_backend/common.py +0 -25
  71. ophyd_async-0.3a3/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -40
  72. ophyd_async-0.3a3/tests/core/test_signal.py +0 -230
  73. ophyd_async-0.3a3/tests/panda/test_writer.py +0 -202
  74. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.codecov.yml +0 -0
  75. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.copier-answers.yml +0 -0
  76. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.devcontainer/devcontainer.json +0 -0
  77. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.git-blame-ignore-revs +0 -0
  78. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/CONTRIBUTING.md +0 -0
  79. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/actions/install_requirements/action.yml +0 -0
  80. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/dependabot.yml +0 -0
  81. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/pages/index.html +0 -0
  82. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/pages/make_switcher.py +0 -0
  83. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_check.yml +0 -0
  84. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_dist.yml +0 -0
  85. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_docs.yml +0 -0
  86. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_pypi.yml +0 -0
  87. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_release.yml +0 -0
  88. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_test.yml +0 -0
  89. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/_tox.yml +0 -0
  90. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/ci.yml +0 -0
  91. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.github/workflows/periodic.yml +0 -0
  92. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.gitignore +0 -0
  93. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.mailmap +0 -0
  94. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/.pre-commit-config.yaml +0 -0
  95. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/Dockerfile +0 -0
  96. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/LICENSE +0 -0
  97. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/README.md +0 -0
  98. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/_templates/README +0 -0
  99. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/_templates/custom-class-template.rst +0 -0
  100. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/_templates/custom-module-template.rst +0 -0
  101. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/conf.py +0 -0
  102. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/examples/epics_demo.py +0 -0
  103. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/examples/foo_detector.py +0 -0
  104. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  105. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  106. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  107. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  108. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  109. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  110. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions/COPYME +0 -0
  111. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/decisions.md +0 -0
  112. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/design-goals.rst +0 -0
  113. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/event-loop-choice.rst +0 -0
  114. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations/flyscanning.rst +0 -0
  115. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/explanations.md +0 -0
  116. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/genindex.rst +0 -0
  117. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/choose-interfaces-for-devices.md +0 -0
  118. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/compound-devices.rst +0 -0
  119. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/contribute.md +0 -0
  120. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to/make-a-standard-detector.rst +0 -0
  121. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/how-to.md +0 -0
  122. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
  123. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/bluesky_ophyd_logo.svg +0 -0
  124. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/hardware-triggered-scan.png +0 -0
  125. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/ophyd_favicon.svg +0 -0
  126. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/outer-scan.png +0 -0
  127. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/images/simple-hardware-scan.png +0 -0
  128. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/index.md +0 -0
  129. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/reference/api.rst +0 -0
  130. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/reference.md +0 -0
  131. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/tutorials/installation.md +0 -0
  132. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/docs/tutorials.md +0 -0
  133. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/setup.cfg +0 -0
  134. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/__init__.py +0 -0
  135. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/__main__.py +0 -0
  136. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/_providers.py +0 -0
  137. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/detector.py +0 -0
  138. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/device_save_loader.py +0 -0
  139. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/flyer.py +0 -0
  140. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/signal_backend.py +0 -0
  141. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/standard_readable.py +0 -0
  142. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/core/utils.py +0 -0
  143. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/__init__.py +0 -0
  144. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/_backend/__init__.py +0 -0
  145. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/aravis.py +0 -0
  146. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
  147. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
  148. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +0 -0
  149. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
  150. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +0 -0
  151. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
  152. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/drivers/__init__.py +0 -0
  153. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
  154. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/pilatus.py +0 -0
  155. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
  156. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
  157. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
  158. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
  159. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
  160. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +0 -0
  161. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/demo/__init__.py +0 -0
  162. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
  163. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/demo/mover.db +0 -0
  164. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/demo/sensor.db +0 -0
  165. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/motion/__init__.py +0 -0
  166. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/pvi/__init__.py +0 -0
  167. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/signal/__init__.py +0 -0
  168. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
  169. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/epics/signal/signal.py +0 -0
  170. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/log.py +0 -0
  171. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/__init__.py +0 -0
  172. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_common_blocks.py +0 -0
  173. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_panda_controller.py +0 -0
  174. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_table.py +0 -0
  175. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_trigger.py +0 -0
  176. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/_utils.py +0 -0
  177. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/writers/__init__.py +0 -0
  178. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/writers/_hdf_writer.py +0 -0
  179. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/panda/writers/_panda_hdf_file.py +0 -0
  180. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/planstubs/__init__.py +0 -0
  181. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/planstubs/prepare_trigger_and_dets.py +0 -0
  182. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/protocols.py +0 -0
  183. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/__init__.py +0 -0
  184. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/demo/__init__.py +0 -0
  185. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
  186. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
  187. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async/sim/sim_pattern_generator.py +0 -0
  188. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  189. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/entry_points.txt +0 -0
  190. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/requires.txt +1 -1
  191. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/src/ophyd_async.egg-info/top_level.txt +0 -0
  192. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/core/test_async_status.py +0 -0
  193. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/__init__.py +0 -0
  194. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/areadetector/test_utils.py +0 -0
  195. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/motion/__init__.py +0 -0
  196. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/epics/test_records.db +0 -0
  197. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/db/panda.db +0 -0
  198. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/panda/test_table.py +0 -0
  199. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/__init__.py +0 -0
  200. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/demo/__init__.py +0 -0
  201. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/demo/test_sim_motor.py +0 -0
  202. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/sim/test_pattern_generator.py +0 -0
  203. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/test_cli.py +0 -0
  204. {ophyd_async-0.3a3 → ophyd_async-0.3a4}/tests/test_log.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3a3
3
+ Version: 0.3a4
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
@@ -48,6 +48,7 @@ Requires-Dist: bluesky>=1.13.0a3
48
48
  Requires-Dist: event-model<1.21.0
49
49
  Requires-Dist: p4p
50
50
  Requires-Dist: pyyaml
51
+ Requires-Dist: colorlog
51
52
  Provides-Extra: ca
52
53
  Requires-Dist: aioca>=1.6; extra == "ca"
53
54
  Provides-Extra: pva
@@ -87,7 +88,6 @@ Requires-Dist: sphinx-design; extra == "dev"
87
88
  Requires-Dist: tox-direct; extra == "dev"
88
89
  Requires-Dist: types-mock; extra == "dev"
89
90
  Requires-Dist: types-pyyaml; extra == "dev"
90
- Requires-Dist: colorlog; extra == "dev"
91
91
 
92
92
  [![CI](https://github.com/bluesky/ophyd-async/actions/workflows/ci.yml/badge.svg)](https://github.com/bluesky/ophyd-async/actions/workflows/ci.yml)
93
93
  [![Coverage](https://codecov.io/gh/bluesky/ophyd-async/branch/main/graph/badge.svg)](https://codecov.io/gh/bluesky/ophyd-async)
@@ -30,7 +30,8 @@ its Python type, which could be:
30
30
 
31
31
  - A primitive (`str`, `int`, `float`)
32
32
  - An array (`numpy.typing.NDArray` or ``Sequence[str]``)
33
- - An enum (`enum.Enum`).
33
+ - An enum (`enum.Enum`) which **must** also extend `str`
34
+ - `str` and ``EnumClass(str, Enum)`` are the only valid ``datatype`` for an enumerated signal.
34
35
 
35
36
  The rest of the arguments are PV connection information, in this case the PV suffix.
36
37
 
@@ -21,19 +21,19 @@ Async Tests
21
21
  ...
22
22
  asyncio_mode = "auto"
23
23
 
24
- Sim Backend
25
- -----------
24
+ Mock Backend
25
+ ------------
26
26
 
27
- Ophyd devices initialized with a sim backend behave in a similar way to mocks, without requiring you to mock out all the dependencies and internals. The `DeviceCollector` can initialize any number of devices, and their signals and sub-devices (recursively), with a sim backend.
27
+ Ophyd devices initialized with a mock backend behave in a similar way to mocks, without requiring you to mock out all the dependencies and internals. The `DeviceCollector` can initialize any number of devices, and their signals and sub-devices (recursively), with a mock backend.
28
28
 
29
29
  .. literalinclude:: ../../tests/epics/demo/test_demo.py
30
- :pyobject: sim_sensor
30
+ :pyobject: mock_sensor
31
31
 
32
32
 
33
- Sim Utility Functions
34
- ---------------------
33
+ Mock Utility Functions
34
+ ----------------------
35
35
 
36
- Sim signals behave as simply as possible, holding a sensible default value when initialized and retaining any value (in memory) to which they are set. This model breaks down in the case of read-only signals, which cannot be set because there is an expectation of some external device setting them in the real world. There is a utility function, ``set_sim_value``, to mock-set values for sim signals, including read-only ones.
36
+ Mock signals behave as simply as possible, holding a sensible default value when initialized and retaining any value (in memory) to which they are set. This model breaks down in the case of read-only signals, which cannot be set because there is an expectation of some external device setting them in the real world. There is a utility function, ``set_mock_value``, to mock-set values for mock signals, including read-only ones.
37
37
 
38
38
  In addition this example also utilizes helper functions like ``assert_reading`` and ``assert_value`` to ensure the validity of device readings and values. For more information see: :doc:`API.core<../generated/ophyd_async.core>`
39
39
 
@@ -41,7 +41,9 @@ In addition this example also utilizes helper functions like ``assert_reading``
41
41
  :pyobject: test_sensor_reading_shows_value
42
42
 
43
43
 
44
- There is another utility function, ``set_sim_callback``, for hooking in logic when a sim value changes (e.g. because someone puts to it).
44
+ There are several other test utility functions:
45
+
46
+ 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.
45
47
 
46
48
  .. literalinclude:: ../../tests/epics/demo/test_demo.py
47
49
  :pyobject: test_mover_stopped
@@ -57,7 +57,7 @@ and run the following:
57
57
  - If ``connect=True`` (the default), then call `Device.connect` in parallel for
58
58
  all top level Devices, waiting for up to ``timeout`` seconds. For example,
59
59
  here we call ``asyncio.wait([det.connect(), samp.connect()])``
60
- - If ``sim=True`` is passed, then don't connect to PVs, but set Devices into
60
+ - If ``mock=True`` is passed, then don't connect to PVs, but set Devices into
61
61
  simulation mode
62
62
 
63
63
  The Devices we create in this example are a "sample stage" with a couple of
@@ -20,6 +20,7 @@ dependencies = [
20
20
  "event-model<1.21.0",
21
21
  "p4p",
22
22
  "pyyaml",
23
+ "colorlog",
23
24
  ]
24
25
  dynamic = ["version"]
25
26
  license.file = "LICENSE"
@@ -64,7 +65,6 @@ dev = [
64
65
  "tox-direct",
65
66
  "types-mock",
66
67
  "types-pyyaml",
67
- "colorlog"
68
68
  ]
69
69
 
70
70
  [project.scripts]
@@ -86,7 +86,6 @@ write_to = "src/ophyd_async/_version.py"
86
86
  addopts = """
87
87
  --tb=native -vv --strict-markers --doctest-modules
88
88
  --doctest-glob="*.rst" --doctest-glob="*.md" --ignore=docs/examples
89
- --cov=src/ophyd_async --cov-report term --cov-report xml:cov.xml
90
89
  """
91
90
  # https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings
92
91
  filterwarnings = "error"
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.3a3'
15
+ __version__ = version = '0.3a4'
16
16
  __version_tuple__ = version_tuple = (0, 3)
@@ -24,6 +24,18 @@ 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
+ )
30
+ from .mock_signal_utils import (
31
+ assert_mock_put_called_with,
32
+ callback_on_mock_put,
33
+ mock_puts_blocked,
34
+ reset_mock_put_calls,
35
+ set_mock_put_proceeds,
36
+ set_mock_value,
37
+ set_mock_values,
38
+ )
27
39
  from .signal import (
28
40
  Signal,
29
41
  SignalR,
@@ -36,15 +48,12 @@ from .signal import (
36
48
  assert_value,
37
49
  observe_value,
38
50
  set_and_wait_for_value,
39
- set_sim_callback,
40
- set_sim_put_proceeds,
41
- set_sim_value,
42
- soft_signal_r_and_backend,
51
+ soft_signal_r_and_setter,
43
52
  soft_signal_rw,
44
53
  wait_for_value,
45
54
  )
46
55
  from .signal_backend import SignalBackend
47
- from .sim_signal_backend import SimSignalBackend
56
+ from .soft_signal_backend import SoftSignalBackend
48
57
  from .standard_readable import ConfigSignal, HintedSignal, StandardReadable
49
58
  from .utils import (
50
59
  DEFAULT_TIMEOUT,
@@ -59,9 +68,15 @@ from .utils import (
59
68
  )
60
69
 
61
70
  __all__ = [
71
+ "assert_mock_put_called_with",
72
+ "callback_on_mock_put",
73
+ "mock_puts_blocked",
74
+ "set_mock_values",
75
+ "reset_mock_put_calls",
62
76
  "SignalBackend",
63
- "SimSignalBackend",
77
+ "SoftSignalBackend",
64
78
  "DetectorControl",
79
+ "MockSignalBackend",
65
80
  "DetectorTrigger",
66
81
  "DetectorWriter",
67
82
  "StandardDetector",
@@ -73,13 +88,12 @@ __all__ = [
73
88
  "SignalW",
74
89
  "SignalRW",
75
90
  "SignalX",
76
- "soft_signal_r_and_backend",
91
+ "soft_signal_r_and_setter",
77
92
  "soft_signal_rw",
78
93
  "observe_value",
79
94
  "set_and_wait_for_value",
80
- "set_sim_callback",
81
- "set_sim_put_proceeds",
82
- "set_sim_value",
95
+ "set_mock_put_proceeds",
96
+ "set_mock_value",
83
97
  "wait_for_value",
84
98
  "AsyncStatus",
85
99
  "DirectoryInfo",
@@ -21,7 +21,9 @@ class AsyncStatus(Status):
21
21
  self.task = awaitable
22
22
  else:
23
23
  self.task = asyncio.create_task(awaitable) # type: ignore
24
+
24
25
  self.task.add_done_callback(self._run_callbacks)
26
+
25
27
  self._callbacks = cast(List[Callback[Status]], [])
26
28
  self._watchers = watchers
27
29
 
@@ -3,6 +3,8 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import sys
6
+ from functools import cached_property
7
+ from logging import LoggerAdapter, getLogger
6
8
  from typing import (
7
9
  Any,
8
10
  Coroutine,
@@ -39,6 +41,12 @@ class Device(HasName):
39
41
  """Return the name of the Device"""
40
42
  return self._name
41
43
 
44
+ @cached_property
45
+ def log(self):
46
+ return LoggerAdapter(
47
+ getLogger("ophyd_async.devices"), {"ophyd_async_device_name": self.name}
48
+ )
49
+
42
50
  def children(self) -> Iterator[Tuple[str, Device]]:
43
51
  for attr_name, attr in self.__dict__.items():
44
52
  if attr_name != "parent" and isinstance(attr, Device):
@@ -52,26 +60,31 @@ class Device(HasName):
52
60
  name:
53
61
  New name to set
54
62
  """
63
+
64
+ # Ensure self.log is recreated after a name change
65
+ if hasattr(self, "log"):
66
+ del self.log
67
+
55
68
  self._name = name
56
69
  for attr_name, child in self.children():
57
70
  child_name = f"{name}-{attr_name.rstrip('_')}" if name else ""
58
71
  child.set_name(child_name)
59
72
  child.parent = self
60
73
 
61
- async def connect(self, sim: bool = False, timeout: float = DEFAULT_TIMEOUT):
74
+ async def connect(self, mock: bool = False, timeout: float = DEFAULT_TIMEOUT):
62
75
  """Connect self and all child Devices.
63
76
 
64
77
  Contains a timeout that gets propagated to child.connect methods.
65
78
 
66
79
  Parameters
67
80
  ----------
68
- sim:
69
- If True then connect in simulation mode.
81
+ mock:
82
+ If True then use ``MockSignalBackend`` for all Signals
70
83
  timeout:
71
84
  Time to wait before failing with a TimeoutError.
72
85
  """
73
86
  coros = {
74
- name: child_device.connect(sim, timeout=timeout)
87
+ name: child_device.connect(mock=mock, timeout=timeout)
75
88
  for name, child_device in self.children()
76
89
  }
77
90
  if coros:
@@ -105,9 +118,9 @@ class DeviceCollector:
105
118
  If True, call ``device.set_name(variable_name)`` on all collected
106
119
  Devices
107
120
  connect:
108
- If True, call ``device.connect(sim)`` in parallel on all
121
+ If True, call ``device.connect(mock)`` in parallel on all
109
122
  collected Devices
110
- sim:
123
+ mock:
111
124
  If True, connect Signals in simulation mode
112
125
  timeout:
113
126
  How long to wait for connect before logging an exception
@@ -129,12 +142,12 @@ class DeviceCollector:
129
142
  self,
130
143
  set_name=True,
131
144
  connect=True,
132
- sim=False,
145
+ mock=False,
133
146
  timeout: float = 10.0,
134
147
  ):
135
148
  self._set_name = set_name
136
149
  self._connect = connect
137
- self._sim = sim
150
+ self._mock = mock
138
151
  self._timeout = timeout
139
152
  self._names_on_enter: Set[str] = set()
140
153
  self._objects_on_exit: Dict[str, Any] = {}
@@ -168,7 +181,7 @@ class DeviceCollector:
168
181
  obj.set_name(name)
169
182
  if self._connect:
170
183
  connect_coroutines[name] = obj.connect(
171
- self._sim, timeout=self._timeout
184
+ self._mock, timeout=self._timeout
172
185
  )
173
186
 
174
187
  # Connect to all the devices
@@ -0,0 +1,86 @@
1
+ import asyncio
2
+ from typing import Optional, Type
3
+ from unittest.mock import MagicMock
4
+
5
+ from bluesky.protocols import Descriptor, Reading
6
+
7
+ from ophyd_async.core.signal_backend import SignalBackend
8
+ from ophyd_async.core.soft_signal_backend import SoftSignalBackend
9
+ from ophyd_async.core.utils import DEFAULT_TIMEOUT, ReadingValueCallback, T
10
+
11
+
12
+ class MockSignalBackend(SignalBackend):
13
+ def __init__(
14
+ self,
15
+ datatype: Optional[Type[T]] = None,
16
+ initial_backend: Optional[SignalBackend[T]] = None,
17
+ ) -> None:
18
+ if isinstance(initial_backend, MockSignalBackend):
19
+ raise ValueError("Cannot make a MockSignalBackend for a MockSignalBackends")
20
+
21
+ self.initial_backend = initial_backend
22
+
23
+ if datatype is None:
24
+ assert (
25
+ self.initial_backend
26
+ ), "Must supply either initial_backend or datatype"
27
+ datatype = self.initial_backend.datatype
28
+
29
+ self.datatype = datatype
30
+
31
+ if not isinstance(self.initial_backend, SoftSignalBackend):
32
+ # If the backend is a hard signal backend, or not provided,
33
+ # then we create a soft signal to mimick it
34
+
35
+ self.soft_backend = SoftSignalBackend(datatype=datatype)
36
+ else:
37
+ self.soft_backend = initial_backend
38
+
39
+ self.mock = MagicMock()
40
+
41
+ self.put_proceeds = asyncio.Event()
42
+ self.put_proceeds.set()
43
+
44
+ def source(self, name: str) -> str:
45
+ self.mock.source(name)
46
+ if self.initial_backend:
47
+ return f"mock+{self.initial_backend.source(name)}"
48
+ return f"mock+{name}"
49
+
50
+ async def connect(self, timeout: float = DEFAULT_TIMEOUT) -> None:
51
+ self.mock.connect(timeout=timeout)
52
+
53
+ async def put(self, value: Optional[T], wait=True, timeout=None):
54
+ self.mock.put(value, wait=wait, timeout=timeout)
55
+ await self.soft_backend.put(value, wait=wait, timeout=timeout)
56
+
57
+ if wait:
58
+ await asyncio.wait_for(self.put_proceeds.wait(), timeout=timeout)
59
+
60
+ def set_value(self, value: T):
61
+ self.mock.set_value(value)
62
+ self.soft_backend.set_value(value)
63
+
64
+ async def get_descriptor(self, source: str) -> Descriptor:
65
+ self.mock.get_descriptor(source)
66
+ return await self.soft_backend.get_descriptor(source)
67
+
68
+ async def get_reading(self) -> Reading:
69
+ self.mock.get_reading()
70
+ return await self.soft_backend.get_reading()
71
+
72
+ async def get_value(self) -> T:
73
+ self.mock.get_value()
74
+ return await self.soft_backend.get_value()
75
+
76
+ async def get_setpoint(self) -> T:
77
+ """For a soft signal, the setpoint and readback values are the same."""
78
+ self.mock.get_setpoint()
79
+ return await self.soft_backend.get_setpoint()
80
+
81
+ async def get_datakey(self, source: str) -> Descriptor:
82
+ return await self.soft_backend.get_datakey(source)
83
+
84
+ def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
85
+ self.mock.set_callback(callback)
86
+ self.soft_backend.set_callback(callback)
@@ -0,0 +1,149 @@
1
+ from contextlib import asynccontextmanager, contextmanager
2
+ from typing import Any, Callable, Generator, Iterable, Iterator, List
3
+ from unittest.mock import ANY
4
+
5
+ from ophyd_async.core.signal import Signal
6
+ from ophyd_async.core.utils import T
7
+
8
+ from .mock_signal_backend import MockSignalBackend
9
+
10
+
11
+ def _get_mock_signal_backend(signal: Signal) -> MockSignalBackend:
12
+ assert isinstance(signal._backend, MockSignalBackend), (
13
+ "Expected to receive a `MockSignalBackend`, instead "
14
+ f" received {type(signal._backend)}. "
15
+ )
16
+ return signal._backend
17
+
18
+
19
+ def set_mock_value(signal: Signal[T], value: T):
20
+ """Set the value of a signal that is in mock mode."""
21
+ backend = _get_mock_signal_backend(signal)
22
+ backend.set_value(value)
23
+
24
+
25
+ def set_mock_put_proceeds(signal: Signal[T], proceeds: bool):
26
+ """Allow or block a put with wait=True from proceeding"""
27
+ backend = _get_mock_signal_backend(signal)
28
+
29
+ if proceeds:
30
+ backend.put_proceeds.set()
31
+ else:
32
+ backend.put_proceeds.clear()
33
+
34
+
35
+ @asynccontextmanager
36
+ async def mock_puts_blocked(*signals: List[Signal]):
37
+ for signal in signals:
38
+ set_mock_put_proceeds(signal, False)
39
+ yield
40
+ for signal in signals:
41
+ set_mock_put_proceeds(signal, True)
42
+
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.mock.put.assert_called_with(value, wait=wait, timeout=timeout)
47
+
48
+
49
+ def reset_mock_put_calls(signal: Signal):
50
+ backend = _get_mock_signal_backend(signal)
51
+ backend.mock.put.reset_mock()
52
+
53
+
54
+ class _SetValuesIterator:
55
+ # Garbage collected by the time __del__ is called unless we put it as a
56
+ # global attrbute here.
57
+ require_all_consumed: bool = False
58
+
59
+ def __init__(
60
+ self,
61
+ signal: Signal,
62
+ values: Iterable[Any],
63
+ require_all_consumed: bool = False,
64
+ ):
65
+ self.signal = signal
66
+ self.values = values
67
+ self.require_all_consumed = require_all_consumed
68
+ self.index = 0
69
+
70
+ self.iterator = enumerate(values, start=1)
71
+
72
+ def __iter__(self):
73
+ return self
74
+
75
+ def __next__(self):
76
+ # Will propogate StopIteration
77
+ self.index, next_value = next(self.iterator)
78
+ set_mock_value(self.signal, next_value)
79
+ return next_value
80
+
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.")
84
+
85
+
86
+ def set_mock_values(
87
+ signal: Signal,
88
+ values: Iterable[Any],
89
+ require_all_consumed: bool = False,
90
+ ) -> Iterator[Any]:
91
+ """Iterator to set a signal to a sequence of values, optionally repeating the
92
+ sequence.
93
+
94
+ Parameters
95
+ ----------
96
+ signal:
97
+ A signal with a `MockSignalBackend` backend.
98
+ values:
99
+ An iterable of the values to set the signal to, on each iteration
100
+ the value will be set.
101
+ require_all_consumed:
102
+ If True, an AssertionError will be raised if the iterator is deleted before
103
+ all values have been consumed.
104
+
105
+ Notes
106
+ -----
107
+ Example usage::
108
+
109
+ for value_set in set_mock_values(signal, [1, 2, 3]):
110
+ # do something
111
+
112
+ cm = set_mock_values(signal, 1, 2, 3, require_all_consumed=True):
113
+ next(cm)
114
+ # do something
115
+ """
116
+
117
+ return _SetValuesIterator(
118
+ signal,
119
+ values,
120
+ require_all_consumed=require_all_consumed,
121
+ )
122
+
123
+
124
+ @contextmanager
125
+ def _unset_side_effect_cm(mock):
126
+ yield
127
+ mock.put.side_effect = None
128
+
129
+
130
+ # linting isn't smart enought to realize @contextmanager will give use a
131
+ # ContextManager[None]
132
+ def callback_on_mock_put(
133
+ signal: Signal, callback: Callable[[T], None]
134
+ ) -> Generator[None, None, None]:
135
+ """For setting a callback when a backend is put to.
136
+
137
+ Can either be used in a context, with the callback being
138
+ unset on exit, or as an ordinary function.
139
+
140
+ Parameters
141
+ ----------
142
+ signal:
143
+ A signal with a `MockSignalBackend` backend.
144
+ callback:
145
+ The callback to call when the backend is put to during the context.
146
+ """
147
+ backend = _get_mock_signal_backend(signal)
148
+ backend.mock.put.side_effect = callback
149
+ return _unset_side_effect_cm(backend.mock)
@@ -24,15 +24,14 @@ from bluesky.protocols import (
24
24
  Subscribable,
25
25
  )
26
26
 
27
+ from ophyd_async.core.mock_signal_backend import MockSignalBackend
27
28
  from ophyd_async.protocols import AsyncConfigurable, AsyncReadable, AsyncStageable
28
29
 
29
30
  from .async_status import AsyncStatus
30
31
  from .device import Device
31
32
  from .signal_backend import SignalBackend
32
- from .sim_signal_backend import SimSignalBackend
33
- from .utils import DEFAULT_TIMEOUT, Callback, ReadingValueCallback, T
34
-
35
- _sim_backends: Dict[Signal, SimSignalBackend] = {}
33
+ from .soft_signal_backend import SoftSignalBackend
34
+ from .utils import DEFAULT_TIMEOUT, Callback, T
36
35
 
37
36
 
38
37
  def _add_timeout(func):
@@ -61,17 +60,17 @@ class Signal(Device, Generic[T]):
61
60
  timeout: Optional[float] = DEFAULT_TIMEOUT,
62
61
  name: str = "",
63
62
  ) -> None:
64
- super().__init__(name)
65
63
  self._timeout = timeout
66
- self._init_backend = self._backend = backend
64
+ self._initial_backend = self._backend = backend
65
+ super().__init__(name)
67
66
 
68
- async def connect(self, sim=False, timeout=DEFAULT_TIMEOUT):
69
- if sim:
70
- self._backend = SimSignalBackend(datatype=self._init_backend.datatype)
71
- _sim_backends[self] = self._backend
72
- else:
73
- self._backend = self._init_backend
74
- _sim_backends.pop(self, None)
67
+ async def connect(self, mock=False, timeout=DEFAULT_TIMEOUT):
68
+ if mock and not isinstance(self._backend, MockSignalBackend):
69
+ # Using a soft backend, look to the initial value
70
+ self._backend = MockSignalBackend(
71
+ initial_backend=self._initial_backend,
72
+ )
73
+ self.log.debug(f"Connecting to {self.source}")
75
74
  await self._backend.connect(timeout=timeout)
76
75
 
77
76
  @property
@@ -96,10 +95,12 @@ class _SignalCache(Generic[T]):
96
95
  self._value: Optional[T] = None
97
96
 
98
97
  self.backend = backend
98
+ signal.log.debug(f"Making subscription on source {signal.source}")
99
99
  backend.set_callback(self._callback)
100
100
 
101
101
  def close(self):
102
102
  self.backend.set_callback(None)
103
+ self._signal.log.debug(f"Closing subscription on source {self._signal.source}")
103
104
 
104
105
  async def get_reading(self) -> Reading:
105
106
  await self._valid.wait()
@@ -112,6 +113,10 @@ class _SignalCache(Generic[T]):
112
113
  return self._value
113
114
 
114
115
  def _callback(self, reading: Reading, value: T):
116
+ self._signal.log.debug(
117
+ f"Updated subscription: reading of source {self._signal.source} changed"
118
+ f"from {self._reading} to {reading}"
119
+ )
115
120
  self._reading = reading
116
121
  self._value = value
117
122
  self._valid.set()
@@ -178,7 +183,9 @@ class SignalR(Signal[T], AsyncReadable, AsyncStageable, Subscribable):
178
183
  @_add_timeout
179
184
  async def get_value(self, cached: Optional[bool] = None) -> T:
180
185
  """The current value"""
181
- return await self._backend_or_cache(cached).get_value()
186
+ value = await self._backend_or_cache(cached).get_value()
187
+ self.log.debug(f"get_value() on source {self.source} returned {value}")
188
+ return value
182
189
 
183
190
  def subscribe_value(self, function: Callback[T]):
184
191
  """Subscribe to updates in value of a device"""
@@ -213,8 +220,15 @@ class SignalW(Signal[T], Movable):
213
220
  """Set the value and return a status saying when it's done"""
214
221
  if timeout is USE_DEFAULT_TIMEOUT:
215
222
  timeout = self._timeout
216
- coro = self._backend.put(value, wait=wait, timeout=timeout)
217
- return AsyncStatus(coro)
223
+
224
+ async def do_set():
225
+ self.log.debug(f"Putting value {value} to backend at source {self.source}")
226
+ await self._backend.put(value, wait=wait, timeout=timeout)
227
+ self.log.debug(
228
+ f"Successfully put value {value} to backend at source {self.source}"
229
+ )
230
+
231
+ return AsyncStatus(do_set())
218
232
 
219
233
 
220
234
  class SignalRW(SignalR[T], SignalW[T], Locatable):
@@ -239,47 +253,29 @@ class SignalX(Signal):
239
253
  return AsyncStatus(coro)
240
254
 
241
255
 
242
- def set_sim_value(signal: Signal[T], value: T):
243
- """Set the value of a signal that is in sim mode."""
244
- _sim_backends[signal]._set_value(value)
245
-
246
-
247
- def set_sim_put_proceeds(signal: Signal[T], proceeds: bool):
248
- """Allow or block a put with wait=True from proceeding"""
249
- event = _sim_backends[signal].put_proceeds
250
- if proceeds:
251
- event.set()
252
- else:
253
- event.clear()
254
-
255
-
256
- def set_sim_callback(signal: Signal[T], callback: ReadingValueCallback[T]) -> None:
257
- """Monitor the value of a signal that is in sim mode"""
258
- return _sim_backends[signal].set_callback(callback)
259
-
260
-
261
256
  def soft_signal_rw(
262
257
  datatype: Optional[Type[T]] = None,
263
258
  initial_value: Optional[T] = None,
264
259
  name: str = "",
265
260
  ) -> SignalRW[T]:
266
- """Creates a read-writable Signal with a SimSignalBackend"""
267
- signal = SignalRW(SimSignalBackend(datatype, initial_value), name=name)
261
+ """Creates a read-writable Signal with a SoftSignalBackend"""
262
+ signal = SignalRW(SoftSignalBackend(datatype, initial_value), name=name)
268
263
  return signal
269
264
 
270
265
 
271
- def soft_signal_r_and_backend(
266
+ def soft_signal_r_and_setter(
272
267
  datatype: Optional[Type[T]] = None,
273
268
  initial_value: Optional[T] = None,
274
269
  name: str = "",
275
- ) -> Tuple[SignalR[T], SimSignalBackend]:
276
- """Returns a tuple of a read-only Signal and its SimSignalBackend through
270
+ ) -> Tuple[SignalR[T], Callable[[T]]]:
271
+ """Returns a tuple of a read-only Signal and a callable through
277
272
  which the signal can be internally modified within the device. Use
278
273
  soft_signal_rw if you want a device that is externally modifiable
279
274
  """
280
- backend = SimSignalBackend(datatype, initial_value)
275
+ backend = SoftSignalBackend(datatype, initial_value)
281
276
  signal = SignalR(backend, name=name)
282
- return (signal, backend)
277
+
278
+ return (signal, backend.set_value)
283
279
 
284
280
 
285
281
  async def assert_value(signal: SignalR[T], value: Any) -> None: