ophyd-async 0.3.2__tar.gz → 0.3.4__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 (203) hide show
  1. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/PKG-INFO +1 -1
  2. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/_version.py +2 -2
  3. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/__init__.py +47 -44
  4. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/signal_backend.py +47 -1
  5. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/soft_signal_backend.py +27 -13
  6. ophyd_async-0.3.4/src/ophyd_async/epics/_backend/common.py +62 -0
  7. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/pilatus_controller.py +4 -1
  8. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/__init__.py +2 -0
  9. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/ad_base.py +32 -0
  10. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/aravis_driver.py +5 -3
  11. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/motion/motor.py +0 -2
  12. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/PKG-INFO +1 -1
  13. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/SOURCES.txt +1 -0
  14. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_soft_signal_backend.py +9 -1
  15. ophyd_async-0.3.4/tests/core/test_subset_enum.py +90 -0
  16. ophyd_async-0.3.4/tests/epics/areadetector/test_drivers.py +96 -0
  17. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_pilatus.py +8 -1
  18. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/demo/test_demo.py +1 -1
  19. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/test_signals.py +27 -7
  20. ophyd_async-0.3.2/src/ophyd_async/epics/_backend/common.py +0 -48
  21. ophyd_async-0.3.2/tests/epics/areadetector/test_drivers.py +0 -47
  22. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.codecov.yml +0 -0
  23. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.copier-answers.yml +0 -0
  24. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.devcontainer/devcontainer.json +0 -0
  25. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.git-blame-ignore-revs +0 -0
  26. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/CONTRIBUTING.md +0 -0
  27. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/actions/install_requirements/action.yml +0 -0
  28. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/dependabot.yml +0 -0
  29. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/pages/index.html +0 -0
  30. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/pages/make_switcher.py +0 -0
  31. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_check.yml +0 -0
  32. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_dist.yml +0 -0
  33. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_docs.yml +0 -0
  34. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_pypi.yml +0 -0
  35. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_release.yml +0 -0
  36. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_test.yml +0 -0
  37. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/_tox.yml +0 -0
  38. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/ci.yml +0 -0
  39. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.github/workflows/periodic.yml +0 -0
  40. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.gitignore +0 -0
  41. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.mailmap +0 -0
  42. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/.pre-commit-config.yaml +0 -0
  43. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/Dockerfile +0 -0
  44. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/LICENSE +0 -0
  45. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/README.md +0 -0
  46. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/_templates/README +0 -0
  47. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/_templates/custom-class-template.rst +0 -0
  48. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/_templates/custom-module-template.rst +0 -0
  49. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/conf.py +0 -0
  50. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/examples/epics_demo.py +0 -0
  51. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/examples/foo_detector.py +0 -0
  52. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  53. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  54. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  55. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  56. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  57. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  58. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions/COPYME +0 -0
  59. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/decisions.md +0 -0
  60. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/design-goals.rst +0 -0
  61. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/event-loop-choice.rst +0 -0
  62. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations/flyscanning.rst +0 -0
  63. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/explanations.md +0 -0
  64. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/genindex.rst +0 -0
  65. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/choose-interfaces-for-devices.md +0 -0
  66. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/compound-devices.rst +0 -0
  67. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/contribute.md +0 -0
  68. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/make-a-simple-device.rst +0 -0
  69. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/make-a-standard-detector.rst +0 -0
  70. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to/write-tests-for-devices.rst +0 -0
  71. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/how-to.md +0 -0
  72. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/images/bluesky_ophyd_epics_devices_logo.svg +0 -0
  73. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/images/bluesky_ophyd_logo.svg +0 -0
  74. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/images/ophyd_favicon.svg +0 -0
  75. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/index.md +0 -0
  76. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/reference/api.rst +0 -0
  77. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/reference.md +0 -0
  78. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/tutorials/installation.md +0 -0
  79. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/tutorials/using-existing-devices.rst +0 -0
  80. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/docs/tutorials.md +0 -0
  81. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/pyproject.toml +0 -0
  82. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/setup.cfg +0 -0
  83. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/__init__.py +0 -0
  84. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/__main__.py +0 -0
  85. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/_providers.py +0 -0
  86. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/async_status.py +0 -0
  87. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/detector.py +0 -0
  88. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/device.py +0 -0
  89. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/device_save_loader.py +0 -0
  90. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/flyer.py +0 -0
  91. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/mock_signal_backend.py +0 -0
  92. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/mock_signal_utils.py +0 -0
  93. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/signal.py +0 -0
  94. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/standard_readable.py +0 -0
  95. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/core/utils.py +0 -0
  96. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/__init__.py +0 -0
  97. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/_backend/__init__.py +0 -0
  98. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/_backend/_aioca.py +0 -0
  99. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/_backend/_p4p.py +0 -0
  100. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/__init__.py +0 -0
  101. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/aravis.py +0 -0
  102. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/__init__.py +0 -0
  103. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/ad_sim_controller.py +0 -0
  104. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/aravis_controller.py +0 -0
  105. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/kinetix_controller.py +0 -0
  106. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/controllers/vimba_controller.py +0 -0
  107. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/kinetix_driver.py +0 -0
  108. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/pilatus_driver.py +0 -0
  109. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/drivers/vimba_driver.py +0 -0
  110. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/kinetix.py +0 -0
  111. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/pilatus.py +0 -0
  112. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/single_trigger_det.py +0 -0
  113. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/utils.py +0 -0
  114. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/vimba.py +0 -0
  115. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/__init__.py +0 -0
  116. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/_hdfdataset.py +0 -0
  117. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/_hdffile.py +0 -0
  118. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/hdf_writer.py +0 -0
  119. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/nd_file_hdf.py +0 -0
  120. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/areadetector/writers/nd_plugin.py +0 -0
  121. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/demo/__init__.py +0 -0
  122. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/demo/demo_ad_sim_detector.py +0 -0
  123. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/demo/mover.db +0 -0
  124. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/demo/sensor.db +0 -0
  125. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/motion/__init__.py +0 -0
  126. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/pvi/__init__.py +0 -0
  127. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/pvi/pvi.py +0 -0
  128. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/signal/__init__.py +0 -0
  129. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/signal/_epics_transport.py +0 -0
  130. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/epics/signal/signal.py +0 -0
  131. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/log.py +0 -0
  132. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/__init__.py +0 -0
  133. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_common_blocks.py +0 -0
  134. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_hdf_panda.py +0 -0
  135. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_panda_controller.py +0 -0
  136. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_table.py +0 -0
  137. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_trigger.py +0 -0
  138. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/_utils.py +0 -0
  139. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/writers/__init__.py +0 -0
  140. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/writers/_hdf_writer.py +0 -0
  141. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/panda/writers/_panda_hdf_file.py +0 -0
  142. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  143. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/plan_stubs/ensure_connected.py +0 -0
  144. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/plan_stubs/fly.py +0 -0
  145. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/protocols.py +0 -0
  146. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/__init__.py +0 -0
  147. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/demo/__init__.py +0 -0
  148. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/demo/sim_motor.py +0 -0
  149. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/pattern_generator.py +0 -0
  150. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/sim_pattern_detector_control.py +0 -0
  151. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/sim_pattern_detector_writer.py +0 -0
  152. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async/sim/sim_pattern_generator.py +0 -0
  153. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  154. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/entry_points.txt +0 -0
  155. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/requires.txt +0 -0
  156. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/src/ophyd_async.egg-info/top_level.txt +0 -0
  157. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/conftest.py +0 -0
  158. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_async_status.py +0 -0
  159. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_device.py +0 -0
  160. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_device_collector.py +0 -0
  161. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_device_save_loader.py +0 -0
  162. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_flyer.py +0 -0
  163. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_mock_signal_backend.py +0 -0
  164. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_signal.py +0 -0
  165. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_standard_readable.py +0 -0
  166. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_utils.py +0 -0
  167. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/core/test_watchable_async_status.py +0 -0
  168. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/_backend/test_common.py +0 -0
  169. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/__init__.py +0 -0
  170. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_aravis.py +0 -0
  171. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_controllers.py +0 -0
  172. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_kinetix.py +0 -0
  173. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_scans.py +0 -0
  174. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_single_trigger_det.py +0 -0
  175. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_utils.py +0 -0
  176. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_vimba.py +0 -0
  177. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/areadetector/test_writers.py +0 -0
  178. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/demo/test_demo_ad_sim_detector.py +0 -0
  179. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/motion/__init__.py +0 -0
  180. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/motion/test_motor.py +0 -0
  181. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/test_pvi.py +0 -0
  182. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/epics/test_records.db +0 -0
  183. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/db/panda.db +0 -0
  184. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_hdf_panda.py +0 -0
  185. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_panda_connect.py +0 -0
  186. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_panda_controller.py +0 -0
  187. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_panda_utils.py +0 -0
  188. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_table.py +0 -0
  189. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_trigger.py +0 -0
  190. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/panda/test_writer.py +0 -0
  191. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/plan_stubs/test_fly.py +0 -0
  192. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/protocols/test_protocols.py +0 -0
  193. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/__init__.py +0 -0
  194. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/conftest.py +0 -0
  195. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/demo/__init__.py +0 -0
  196. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/demo/test_sim_motor.py +0 -0
  197. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/test_pattern_generator.py +0 -0
  198. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/test_sim_detector.py +0 -0
  199. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/test_sim_writer.py +0 -0
  200. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/sim/test_streaming_plan.py +0 -0
  201. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/test_cli.py +0 -0
  202. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/test_data/test_yaml_save.yml +0 -0
  203. {ophyd_async-0.3.2 → ophyd_async-0.3.4}/tests/test_log.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3.2
3
+ Version: 0.3.4
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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.3.2'
16
- __version_tuple__ = version_tuple = (0, 3, 2)
15
+ __version__ = version = '0.3.4'
16
+ __version_tuple__ = version_tuple = (0, 3, 4)
@@ -50,7 +50,7 @@ from .signal import (
50
50
  soft_signal_rw,
51
51
  wait_for_value,
52
52
  )
53
- from .signal_backend import SignalBackend
53
+ from .signal_backend import RuntimeSubsetEnum, SignalBackend, SubsetEnum
54
54
  from .soft_signal_backend import SoftSignalBackend
55
55
  from .standard_readable import ConfigSignal, HintedSignal, StandardReadable
56
56
  from .utils import (
@@ -68,66 +68,69 @@ from .utils import (
68
68
  )
69
69
 
70
70
  __all__ = [
71
- "get_mock_put",
72
- "callback_on_mock_put",
73
- "mock_puts_blocked",
74
- "set_mock_values",
75
- "reset_mock_put_calls",
76
- "SignalBackend",
77
- "SoftSignalBackend",
71
+ "AsyncStatus",
72
+ "CalculatableTimeout",
73
+ "CalculateTimeout",
74
+ "Callback",
75
+ "ConfigSignal",
76
+ "DEFAULT_TIMEOUT",
78
77
  "DetectorControl",
79
- "MockSignalBackend",
80
78
  "DetectorTrigger",
81
79
  "DetectorWriter",
82
- "StandardDetector",
83
80
  "Device",
84
81
  "DeviceCollector",
85
82
  "DeviceVector",
86
- "Signal",
87
- "SignalR",
88
- "SignalW",
89
- "SignalRW",
90
- "SignalX",
91
- "soft_signal_r_and_setter",
92
- "soft_signal_rw",
93
- "observe_value",
94
- "set_and_wait_for_value",
95
- "set_mock_put_proceeds",
96
- "set_mock_value",
97
- "wait_for_value",
98
- "AsyncStatus",
99
- "WatchableAsyncStatus",
100
83
  "DirectoryInfo",
101
84
  "DirectoryProvider",
85
+ "HardwareTriggeredFlyable",
86
+ "HintedSignal",
87
+ "MockSignalBackend",
102
88
  "NameProvider",
89
+ "NotConnected",
90
+ "ReadingValueCallback",
91
+ "RuntimeSubsetEnum",
92
+ "SubsetEnum",
103
93
  "ShapeProvider",
104
- "StaticDirectoryProvider",
94
+ "Signal",
95
+ "SignalBackend",
96
+ "SignalR",
97
+ "SignalRW",
98
+ "SignalW",
99
+ "SignalX",
100
+ "SoftSignalBackend",
101
+ "StandardDetector",
105
102
  "StandardReadable",
106
- "ConfigSignal",
107
- "HintedSignal",
103
+ "StaticDirectoryProvider",
104
+ "T",
108
105
  "TriggerInfo",
109
106
  "TriggerLogic",
110
- "HardwareTriggeredFlyable",
111
- "CalculateTimeout",
112
- "CalculatableTimeout",
113
- "DEFAULT_TIMEOUT",
114
- "Callback",
115
- "NotConnected",
116
- "ReadingValueCallback",
117
- "T",
107
+ "WatchableAsyncStatus",
108
+ "assert_configuration",
109
+ "assert_emitted",
110
+ "assert_mock_put_called_with",
111
+ "assert_reading",
112
+ "assert_value",
113
+ "callback_on_mock_put",
118
114
  "get_dtype",
119
- "get_unique",
120
- "merge_gathered_dicts",
121
- "wait_for_connection",
115
+ "get_mock_put",
122
116
  "get_signal_values",
117
+ "get_unique",
118
+ "load_device",
123
119
  "load_from_yaml",
120
+ "merge_gathered_dicts",
121
+ "mock_puts_blocked",
122
+ "observe_value",
123
+ "reset_mock_put_calls",
124
+ "save_device",
124
125
  "save_to_yaml",
126
+ "set_and_wait_for_value",
127
+ "set_mock_put_proceeds",
128
+ "set_mock_value",
129
+ "set_mock_values",
125
130
  "set_signal_values",
131
+ "soft_signal_r_and_setter",
132
+ "soft_signal_rw",
133
+ "wait_for_connection",
134
+ "wait_for_value",
126
135
  "walk_rw_signals",
127
- "load_device",
128
- "save_device",
129
- "assert_reading",
130
- "assert_value",
131
- "assert_configuration",
132
- "assert_emitted",
133
136
  ]
@@ -1,5 +1,13 @@
1
1
  from abc import abstractmethod
2
- from typing import Generic, Optional, Type
2
+ from typing import (
3
+ TYPE_CHECKING,
4
+ ClassVar,
5
+ Generic,
6
+ Literal,
7
+ Optional,
8
+ Tuple,
9
+ Type,
10
+ )
3
11
 
4
12
  from bluesky.protocols import DataKey, Reading
5
13
 
@@ -45,3 +53,41 @@ class SignalBackend(Generic[T]):
45
53
  @abstractmethod
46
54
  def set_callback(self, callback: Optional[ReadingValueCallback[T]]) -> None:
47
55
  """Observe changes to the current value, timestamp and severity"""
56
+
57
+
58
+ class _RuntimeSubsetEnumMeta(type):
59
+ def __str__(cls):
60
+ if hasattr(cls, "choices"):
61
+ return f"SubsetEnum{list(cls.choices)}"
62
+ return "SubsetEnum"
63
+
64
+ def __getitem__(cls, _choices):
65
+ if isinstance(_choices, str):
66
+ _choices = (_choices,)
67
+ else:
68
+ if not isinstance(_choices, tuple) or not all(
69
+ isinstance(c, str) for c in _choices
70
+ ):
71
+ raise TypeError(
72
+ "Choices must be a str or a tuple of str, " f"not {type(_choices)}."
73
+ )
74
+ if len(set(_choices)) != len(_choices):
75
+ raise TypeError("Duplicate elements in runtime enum choices.")
76
+
77
+ class _RuntimeSubsetEnum(cls):
78
+ choices = _choices
79
+
80
+ return _RuntimeSubsetEnum
81
+
82
+
83
+ class RuntimeSubsetEnum(metaclass=_RuntimeSubsetEnumMeta):
84
+ choices: ClassVar[Tuple[str, ...]]
85
+
86
+ def __init__(self):
87
+ raise RuntimeError("SubsetEnum cannot be instantiated")
88
+
89
+
90
+ if TYPE_CHECKING:
91
+ SubsetEnum = Literal
92
+ else:
93
+ SubsetEnum = RuntimeSubsetEnum
@@ -3,14 +3,23 @@ from __future__ import annotations
3
3
  import inspect
4
4
  import time
5
5
  from collections import abc
6
- from dataclasses import dataclass
7
6
  from enum import Enum
8
- from typing import Dict, Generic, Optional, Type, TypedDict, Union, cast, get_origin
7
+ from typing import (
8
+ Dict,
9
+ Generic,
10
+ Optional,
11
+ Tuple,
12
+ Type,
13
+ TypedDict,
14
+ Union,
15
+ cast,
16
+ get_origin,
17
+ )
9
18
 
10
19
  import numpy as np
11
20
  from bluesky.protocols import DataKey, Dtype, Reading
12
21
 
13
- from .signal_backend import SignalBackend
22
+ from .signal_backend import RuntimeSubsetEnum, SignalBackend
14
23
  from .utils import DEFAULT_TIMEOUT, ReadingValueCallback, T, get_dtype
15
24
 
16
25
  primitive_dtypes: Dict[type, Dtype] = {
@@ -74,23 +83,24 @@ class SoftArrayConverter(SoftConverter):
74
83
  return cast(T, datatype(shape=0)) # type: ignore
75
84
 
76
85
 
77
- @dataclass
78
86
  class SoftEnumConverter(SoftConverter):
79
- enum_class: Type[Enum]
87
+ choices: Tuple[str, ...]
80
88
 
81
- def write_value(self, value: Union[Enum, str]) -> Enum:
82
- if isinstance(value, Enum):
83
- return value
89
+ def __init__(self, datatype: Union[RuntimeSubsetEnum, Enum]):
90
+ if issubclass(datatype, Enum):
91
+ self.choices = tuple(v.value for v in datatype)
84
92
  else:
85
- return self.enum_class(value)
93
+ self.choices = datatype.choices
94
+
95
+ def write_value(self, value: Union[Enum, str]) -> str:
96
+ return value
86
97
 
87
98
  def get_datakey(self, source: str, value, **metadata) -> DataKey:
88
- choices = [e.value for e in self.enum_class]
89
99
  return {
90
100
  "source": source,
91
101
  "dtype": "string",
92
102
  "shape": [],
93
- "choices": choices,
103
+ "choices": self.choices,
94
104
  **metadata,
95
105
  }
96
106
 
@@ -98,13 +108,17 @@ class SoftEnumConverter(SoftConverter):
98
108
  if datatype is None:
99
109
  return cast(T, None)
100
110
 
101
- return cast(T, list(datatype.__members__.values())[0]) # type: ignore
111
+ if issubclass(datatype, Enum):
112
+ return cast(T, list(datatype.__members__.values())[0]) # type: ignore
113
+ return cast(T, self.choices[0])
102
114
 
103
115
 
104
116
  def make_converter(datatype):
105
117
  is_array = get_dtype(datatype) is not None
106
118
  is_sequence = get_origin(datatype) == abc.Sequence
107
- is_enum = issubclass(datatype, Enum) if inspect.isclass(datatype) else False
119
+ is_enum = inspect.isclass(datatype) and (
120
+ issubclass(datatype, Enum) or issubclass(datatype, RuntimeSubsetEnum)
121
+ )
108
122
 
109
123
  if is_array or is_sequence:
110
124
  return SoftArrayConverter()
@@ -0,0 +1,62 @@
1
+ import inspect
2
+ from enum import Enum
3
+ from typing import Dict, Optional, Tuple, Type, TypedDict
4
+
5
+ from ophyd_async.core.signal_backend import RuntimeSubsetEnum
6
+
7
+ common_meta = {
8
+ "units",
9
+ "precision",
10
+ }
11
+
12
+
13
+ class LimitPair(TypedDict):
14
+ high: float | None
15
+ low: float | None
16
+
17
+ def __bool__(self) -> bool:
18
+ return self.low is None and self.high is None
19
+
20
+
21
+ class Limits(TypedDict):
22
+ alarm: LimitPair
23
+ control: LimitPair
24
+ display: LimitPair
25
+ warning: LimitPair
26
+
27
+ def __bool__(self) -> bool:
28
+ return any(self.alarm, self.control, self.display, self.warning)
29
+
30
+
31
+ def get_supported_values(
32
+ pv: str,
33
+ datatype: Optional[Type[str]],
34
+ pv_choices: Tuple[str, ...],
35
+ ) -> Dict[str, str]:
36
+ if inspect.isclass(datatype) and issubclass(datatype, RuntimeSubsetEnum):
37
+ if not set(datatype.choices).issubset(set(pv_choices)):
38
+ raise TypeError(
39
+ f"{pv} has choices {pv_choices}, "
40
+ f"which is not a superset of {str(datatype)}."
41
+ )
42
+ return {x: x or "_" for x in pv_choices}
43
+ elif inspect.isclass(datatype) and issubclass(datatype, Enum):
44
+ if not issubclass(datatype, str):
45
+ raise TypeError(
46
+ f"{pv} is type Enum but {datatype} does not inherit from String."
47
+ )
48
+
49
+ choices = tuple(v.value for v in datatype)
50
+ if set(choices) != set(pv_choices):
51
+ raise TypeError(
52
+ f"{pv} has choices {pv_choices}, "
53
+ f"which do not match {datatype}, which has {choices}."
54
+ )
55
+ return {x: datatype(x) if x else "_" for x in pv_choices}
56
+ elif datatype is None:
57
+ return {x: x or "_" for x in pv_choices}
58
+
59
+ raise TypeError(
60
+ f"{pv} has choices {pv_choices}. "
61
+ "Use an Enum or SubsetEnum to represent this."
62
+ )
@@ -5,6 +5,7 @@ from ophyd_async.core import DEFAULT_TIMEOUT, wait_for_value
5
5
  from ophyd_async.core.async_status import AsyncStatus
6
6
  from ophyd_async.core.detector import DetectorControl, DetectorTrigger
7
7
  from ophyd_async.epics.areadetector.drivers.ad_base import (
8
+ set_exposure_time_and_acquire_period_if_supplied,
8
9
  start_acquiring_driver_and_ensure_status,
9
10
  )
10
11
  from ophyd_async.epics.areadetector.drivers.pilatus_driver import (
@@ -39,7 +40,9 @@ class PilatusController(DetectorControl):
39
40
  exposure: Optional[float] = None,
40
41
  ) -> AsyncStatus:
41
42
  if exposure is not None:
42
- await self._drv.acquire_time.set(exposure)
43
+ await set_exposure_time_and_acquire_period_if_supplied(
44
+ self, self._drv, exposure
45
+ )
43
46
  await asyncio.gather(
44
47
  self._drv.trigger_mode.set(self._get_trigger_mode(trigger)),
45
48
  self._drv.num_images.set(999_999 if num == 0 else num),
@@ -2,6 +2,7 @@ from .ad_base import (
2
2
  ADBase,
3
3
  ADBaseShapeProvider,
4
4
  DetectorState,
5
+ set_exposure_time_and_acquire_period_if_supplied,
5
6
  start_acquiring_driver_and_ensure_status,
6
7
  )
7
8
  from .aravis_driver import AravisDriver
@@ -17,5 +18,6 @@ __all__ = [
17
18
  "KinetixDriver",
18
19
  "VimbaDriver",
19
20
  "start_acquiring_driver_and_ensure_status",
21
+ "set_exposure_time_and_acquire_period_if_supplied",
20
22
  "DetectorState",
21
23
  ]
@@ -5,6 +5,7 @@ from typing import FrozenSet, Sequence, Set
5
5
  from ophyd_async.core import (
6
6
  DEFAULT_TIMEOUT,
7
7
  AsyncStatus,
8
+ DetectorControl,
8
9
  ShapeProvider,
9
10
  set_and_wait_for_value,
10
11
  )
@@ -44,6 +45,7 @@ class ADBase(NDArrayBase):
44
45
  def __init__(self, prefix: str, name: str = "") -> None:
45
46
  # Define some signals
46
47
  self.acquire_time = epics_signal_rw_rbv(float, prefix + "AcquireTime")
48
+ self.acquire_period = epics_signal_rw_rbv(float, prefix + "AcquirePeriod")
47
49
  self.num_images = epics_signal_rw_rbv(int, prefix + "NumImages")
48
50
  self.image_mode = epics_signal_rw_rbv(ImageMode, prefix + "ImageMode")
49
51
  self.detector_state = epics_signal_r(
@@ -52,6 +54,36 @@ class ADBase(NDArrayBase):
52
54
  super().__init__(prefix, name=name)
53
55
 
54
56
 
57
+ async def set_exposure_time_and_acquire_period_if_supplied(
58
+ controller: DetectorControl,
59
+ driver: ADBase,
60
+ exposure: float | None = None,
61
+ timeout: float = DEFAULT_TIMEOUT,
62
+ ) -> None:
63
+ """
64
+ Sets the exposure time if it is not None and the acquire period to the
65
+ exposure time plus the deadtime. This is expected behavior for most
66
+ AreaDetectors, but some may require more specialized handling.
67
+
68
+ Parameters
69
+ ----------
70
+ controller:
71
+ Controller that can supply a deadtime.
72
+ driver:
73
+ The driver to start acquiring. Must subclass ADBase.
74
+ exposure:
75
+ Desired exposure time, this is a noop if it is None.
76
+ timeout:
77
+ How long to wait for the exposure time and acquire period to be set.
78
+ """
79
+ if exposure is not None:
80
+ full_frame_time = exposure + controller.get_deadtime(exposure)
81
+ await asyncio.gather(
82
+ driver.acquire_time.set(exposure, timeout=timeout),
83
+ driver.acquire_period.set(full_frame_time, timeout=timeout),
84
+ )
85
+
86
+
55
87
  async def start_acquiring_driver_and_ensure_status(
56
88
  driver: ADBase,
57
89
  good_states: Set[DetectorState] = set(DEFAULT_GOOD_STATES),
@@ -1,6 +1,6 @@
1
1
  from enum import Enum
2
- from typing import Literal
3
2
 
3
+ from ophyd_async.core import SubsetEnum
4
4
  from ophyd_async.epics.areadetector.drivers import ADBase
5
5
  from ophyd_async.epics.signal.signal import epics_signal_rw_rbv
6
6
 
@@ -19,7 +19,7 @@ class AravisTriggerMode(str, Enum):
19
19
  To prevent requiring one Enum class per possible configuration, we set as this Enum
20
20
  but read from the underlying signal as a str.
21
21
  """
22
- AravisTriggerSource = Literal["Freerun", "Line1", "Line2", "Line3", "Line4"]
22
+ AravisTriggerSource = SubsetEnum["Freerun", "Line1"]
23
23
 
24
24
 
25
25
  class AravisDriver(ADBase):
@@ -34,5 +34,7 @@ class AravisDriver(ADBase):
34
34
  self.trigger_mode = epics_signal_rw_rbv(
35
35
  AravisTriggerMode, prefix + "TriggerMode"
36
36
  )
37
- self.trigger_source = epics_signal_rw_rbv(str, prefix + "TriggerSource")
37
+ self.trigger_source = epics_signal_rw_rbv(
38
+ AravisTriggerSource, prefix + "TriggerSource"
39
+ )
38
40
  super().__init__(prefix, name=name)
@@ -95,5 +95,3 @@ class Motor(StandardReadable, Movable, Stoppable):
95
95
  # Put with completion will never complete as we are waiting for completion on
96
96
  # the move above, so need to pass wait=False
97
97
  await self.motor_stop.trigger(wait=False)
98
- # Trigger any callbacks
99
- await self.user_readback._backend.put(await self.user_readback.get_value())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ophyd-async
3
- Version: 0.3.2
3
+ Version: 0.3.4
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
@@ -156,6 +156,7 @@ tests/core/test_mock_signal_backend.py
156
156
  tests/core/test_signal.py
157
157
  tests/core/test_soft_signal_backend.py
158
158
  tests/core/test_standard_readable.py
159
+ tests/core/test_subset_enum.py
159
160
  tests/core/test_utils.py
160
161
  tests/core/test_watchable_async_status.py
161
162
  tests/epics/test_pvi.py
@@ -31,7 +31,7 @@ def string_d(value):
31
31
 
32
32
 
33
33
  def enum_d(value):
34
- return {"dtype": "string", "shape": [], "choices": ["Aaa", "Bbb", "Ccc"]}
34
+ return {"dtype": "string", "shape": [], "choices": ("Aaa", "Bbb", "Ccc")}
35
35
 
36
36
 
37
37
  def waveform_d(value):
@@ -115,6 +115,14 @@ async def test_soft_signal_backend_get_put_monitor(
115
115
  q.close()
116
116
 
117
117
 
118
+ async def test_soft_signal_backend_enum_value_equivalence():
119
+ soft_signal = SoftSignalBackend(MyEnum)
120
+ await soft_signal.connect()
121
+ assert (await soft_signal.get_value()) is MyEnum.a
122
+ await soft_signal.put(MyEnum.b)
123
+ assert (await soft_signal.get_value()) is MyEnum.b
124
+
125
+
118
126
  async def test_soft_signal_backend_with_numpy_typing():
119
127
  soft_backend = SoftSignalBackend(npt.NDArray[np.float64])
120
128
  await soft_backend.connect()
@@ -0,0 +1,90 @@
1
+ import pytest
2
+ from epicscorelibs.ca import dbr
3
+ from p4p import Value as P4PValue
4
+ from p4p.nt import NTEnum
5
+
6
+ from ophyd_async.core import SubsetEnum
7
+ from ophyd_async.epics._backend._aioca import make_converter as aioca_make_converter
8
+ from ophyd_async.epics._backend._p4p import make_converter as p4p_make_converter
9
+ from ophyd_async.epics.signal.signal import epics_signal_rw
10
+
11
+
12
+ async def test_runtime_enum_behaviour():
13
+ rt_enum = SubsetEnum["A", "B"]
14
+
15
+ with pytest.raises(RuntimeError) as exc:
16
+ rt_enum()
17
+ assert str(exc.value) == "SubsetEnum cannot be instantiated"
18
+
19
+ assert issubclass(rt_enum, SubsetEnum)
20
+
21
+ # Our metaclass doesn't cache already created runtime enums,
22
+ # so we can't do this
23
+ assert not issubclass(rt_enum, SubsetEnum["A", "B"])
24
+ assert not issubclass(rt_enum, SubsetEnum["B", "A"])
25
+ assert rt_enum is not SubsetEnum["A", "B"]
26
+ assert rt_enum is not SubsetEnum["B", "A"]
27
+
28
+ assert str(rt_enum) == "SubsetEnum['A', 'B']"
29
+ assert str(SubsetEnum) == "SubsetEnum"
30
+
31
+ with pytest.raises(TypeError) as exc:
32
+ SubsetEnum["A", "B", "A"]
33
+ assert str(exc.value) == "Duplicate elements in runtime enum choices."
34
+
35
+
36
+ async def test_ca_runtime_enum_converter():
37
+ class EpicsValue:
38
+ def __init__(self):
39
+ self.name = "test"
40
+ self.ok = (True,)
41
+ self.errorcode = 0
42
+ self.datatype = dbr.DBR_ENUM
43
+ self.element_count = 1
44
+ self.severity = 0
45
+ self.status = 0
46
+ self.raw_stamp = (0,)
47
+ self.timestamp = 0
48
+ self.datetime = 0
49
+ self.enums = ["A", "B", "C"] # More than the runtime enum
50
+
51
+ epics_value = EpicsValue()
52
+ rt_enum = SubsetEnum["A", "B"]
53
+ converter = aioca_make_converter(
54
+ rt_enum, values={"READ_PV": epics_value, "WRITE_PV": epics_value}
55
+ )
56
+ assert converter.choices == {"A": "A", "B": "B", "C": "C"}
57
+ assert set(rt_enum.choices).issubset(set(converter.choices.keys()))
58
+
59
+
60
+ async def test_pva_runtime_enum_converter():
61
+ enum_type = NTEnum.buildType()
62
+ epics_value = P4PValue(
63
+ enum_type,
64
+ {
65
+ "value.choices": ["A", "B", "C"],
66
+ },
67
+ )
68
+ rt_enum = SubsetEnum["A", "B"]
69
+ converter = p4p_make_converter(
70
+ rt_enum, values={"READ_PV": epics_value, "WRITE_PV": epics_value}
71
+ )
72
+ assert {"A", "B"}.issubset(set(converter.choices))
73
+
74
+
75
+ async def test_runtime_enum_signal():
76
+ signal_rw_pva = epics_signal_rw(SubsetEnum["A1", "B1"], "ca://RW_PV", name="signal")
77
+ signal_rw_ca = epics_signal_rw(SubsetEnum["A2", "B2"], "ca://RW_PV", name="signal")
78
+ await signal_rw_pva.connect(mock=True)
79
+ await signal_rw_ca.connect(mock=True)
80
+ await signal_rw_pva.get_value() == "A1"
81
+ await signal_rw_ca.get_value() == "A2"
82
+ await signal_rw_pva.set("B1")
83
+ await signal_rw_ca.set("B2")
84
+ await signal_rw_pva.get_value() == "B1"
85
+ await signal_rw_ca.get_value() == "B2"
86
+
87
+ # Will accept string values even if they're not in the runtime enum
88
+ # Though type checking should compain
89
+ await signal_rw_pva.set("C1") # type: ignore
90
+ await signal_rw_ca.set("C2") # type: ignore