ophyd-async 0.14.0__tar.gz → 0.14.2__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 (329) hide show
  1. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.copier-answers.yml +1 -1
  2. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/CONTRIBUTING.md +1 -1
  3. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_test.yml +0 -5
  4. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/ci.yml +4 -2
  5. ophyd_async-0.14.2/.github/workflows/claude.yml +52 -0
  6. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.pre-commit-config.yaml +1 -1
  7. {ophyd_async-0.14.0/src/ophyd_async.egg-info → ophyd_async-0.14.2}/PKG-INFO +1 -1
  8. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/_version.py +3 -3
  9. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/__init__.py +2 -0
  10. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_derived_signal.py +56 -23
  11. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_device_filler.py +28 -3
  12. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_providers.py +94 -1
  13. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/pmac/_pmac_trajectory.py +15 -1
  14. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/eiger/_eiger_io.py +1 -1
  15. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_control.py +2 -1
  16. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/__init__.py +6 -0
  17. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/_tango_transport.py +12 -11
  18. {ophyd_async-0.14.0 → ophyd_async-0.14.2/src/ophyd_async.egg-info}/PKG-INFO +1 -1
  19. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async.egg-info/SOURCES.txt +6 -5
  20. {ophyd_async-0.14.0/tests/system_tests/tango → ophyd_async-0.14.2/tests/system_tests_tango}/conftest.py +20 -8
  21. {ophyd_async-0.14.0/tests/system_tests/tango → ophyd_async-0.14.2/tests/system_tests_tango}/test_tango_signals.py +22 -12
  22. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_device.py +48 -0
  23. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_multi_derived_signal.py +62 -0
  24. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_observe.py +8 -4
  25. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_providers.py +57 -0
  26. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_single_derived_signal.py +24 -1
  27. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pmac/test_pmac_trajectory.py +35 -16
  28. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pvi/test_pvi.py +17 -0
  29. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.codecov.yml +0 -0
  30. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.devcontainer/devcontainer.json +0 -0
  31. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.git-blame-ignore-revs +0 -0
  32. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  33. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/ISSUE_TEMPLATE/issue.md +0 -0
  34. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +0 -0
  35. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/codeql/codeql-config.yml +0 -0
  36. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/pages/index.html +0 -0
  37. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/pages/make_switcher.py +0 -0
  38. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_codeql.yml +0 -0
  39. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_dist.yml +0 -0
  40. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_docs.yml +0 -0
  41. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_pypi.yml +0 -0
  42. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_release.yml +0 -0
  43. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/_tox.yml +0 -0
  44. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.github/workflows/periodic.yml +0 -0
  45. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.gitignore +0 -0
  46. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.gitleaks.toml +0 -0
  47. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.gitmodules +0 -0
  48. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/.python-version +0 -0
  49. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/Dockerfile +0 -0
  50. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/LICENSE +0 -0
  51. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/README.md +0 -0
  52. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/_static/custom.css +0 -0
  53. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/conf.py +0 -0
  54. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0001-record-architecture-decisions.md +0 -0
  55. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0002-switched-to-python-copier-template.md +0 -0
  56. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0003-ophyd-async-migration.rst +0 -0
  57. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0004-repository-structure.rst +0 -0
  58. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0005-respect-black-line-length.rst +0 -0
  59. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0006-procedural-device-definitions.rst +0 -0
  60. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0007-subpackage-structure.md +0 -0
  61. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0008-signal-types.md +0 -0
  62. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0009-procedural-vs-declarative-devices.md +0 -0
  63. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0010-docstring-format.md +0 -0
  64. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/0011-buffer-updates-camonitor.md +0 -0
  65. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions/COPYME +0 -0
  66. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/decisions.md +0 -0
  67. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/declarative-vs-procedural.md +0 -0
  68. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/design-goals.md +0 -0
  69. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/device-connection-strategies.md +0 -0
  70. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/devices-signals-backends.md +0 -0
  71. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/fly-scanning.md +0 -0
  72. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/plan-stubs.md +0 -0
  73. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/when-to-extend-movable.md +0 -0
  74. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations/where-device-logic.md +0 -0
  75. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/explanations.md +0 -0
  76. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/genindex.rst +0 -0
  77. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/choose-right-baseclass.md +0 -0
  78. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/contribute.md +0 -0
  79. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/derive-one-signal-from-others.md +0 -0
  80. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/implement-ad-detector.md +0 -0
  81. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/interact-with-signals.md +0 -0
  82. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/put-device-back.md +0 -0
  83. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to/store-and-retrieve.md +0 -0
  84. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/how-to.md +0 -0
  85. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/images/fly_scan_collection_windows_and_frames.svg +0 -0
  86. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/images/ophyd-async-logo.svg +0 -0
  87. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/images/ophyd-favicon.svg +0 -0
  88. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/images/set_and_wait_for_other_value.excalidraw.svg +0 -0
  89. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/index.md +0 -0
  90. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/reference.md +0 -0
  91. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials/implementing-detectors.md +0 -0
  92. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials/implementing-devices.md +0 -0
  93. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials/installation.md +0 -0
  94. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials/using-devices.md +0 -0
  95. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials/writing-tests-for-devices.md +0 -0
  96. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/docs/tutorials.md +0 -0
  97. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/pyproject.toml +0 -0
  98. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/renovate.json +0 -0
  99. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/setup.cfg +0 -0
  100. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/__init__.py +0 -0
  101. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/__main__.py +0 -0
  102. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/_docs_parser.py +0 -0
  103. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_derived_signal_backend.py +0 -0
  104. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_detector.py +0 -0
  105. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_device.py +0 -0
  106. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_enums.py +0 -0
  107. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_flyer.py +0 -0
  108. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_hdf_dataset.py +0 -0
  109. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_log.py +0 -0
  110. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_mock_signal_backend.py +0 -0
  111. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_mock_signal_utils.py +0 -0
  112. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_protocol.py +0 -0
  113. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_readable.py +0 -0
  114. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_settings.py +0 -0
  115. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_signal.py +0 -0
  116. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_signal_backend.py +0 -0
  117. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_soft_signal_backend.py +0 -0
  118. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_status.py +0 -0
  119. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_table.py +0 -0
  120. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_utils.py +0 -0
  121. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/core/_yaml_settings.py +0 -0
  122. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/__init__.py +0 -0
  123. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adandor/__init__.py +0 -0
  124. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adandor/_andor.py +0 -0
  125. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adandor/_andor_controller.py +0 -0
  126. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adandor/_andor_io.py +0 -0
  127. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adaravis/__init__.py +0 -0
  128. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adaravis/_aravis.py +0 -0
  129. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adaravis/_aravis_controller.py +0 -0
  130. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adaravis/_aravis_io.py +0 -0
  131. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/__init__.py +0 -0
  132. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_core_detector.py +0 -0
  133. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_core_io.py +0 -0
  134. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_core_logic.py +0 -0
  135. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_core_writer.py +0 -0
  136. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_hdf_writer.py +0 -0
  137. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_jpeg_writer.py +0 -0
  138. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_single_trigger.py +0 -0
  139. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_tiff_writer.py +0 -0
  140. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adcore/_utils.py +0 -0
  141. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adkinetix/__init__.py +0 -0
  142. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adkinetix/_kinetix.py +0 -0
  143. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adkinetix/_kinetix_controller.py +0 -0
  144. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adkinetix/_kinetix_io.py +0 -0
  145. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adpilatus/__init__.py +0 -0
  146. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adpilatus/_pilatus.py +0 -0
  147. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adpilatus/_pilatus_controller.py +0 -0
  148. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adpilatus/_pilatus_io.py +0 -0
  149. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adsimdetector/__init__.py +0 -0
  150. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adsimdetector/_sim.py +0 -0
  151. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adsimdetector/_sim_controller.py +0 -0
  152. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/adsimdetector/_sim_io.py +0 -0
  153. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/advimba/__init__.py +0 -0
  154. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/advimba/_vimba.py +0 -0
  155. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/advimba/_vimba_controller.py +0 -0
  156. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/advimba/_vimba_io.py +0 -0
  157. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/__init__.py +0 -0
  158. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_aioca.py +0 -0
  159. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_epics_connector.py +0 -0
  160. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_epics_device.py +0 -0
  161. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_p4p.py +0 -0
  162. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_pvi_connector.py +0 -0
  163. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_signal.py +0 -0
  164. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/core/_util.py +0 -0
  165. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/__init__.py +0 -0
  166. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/__main__.py +0 -0
  167. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/_ioc.py +0 -0
  168. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/_motor.py +0 -0
  169. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/_point_detector.py +0 -0
  170. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/_point_detector_channel.py +0 -0
  171. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/_stage.py +0 -0
  172. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/motor.db +0 -0
  173. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/point_detector.db +0 -0
  174. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/demo/point_detector_channel.db +0 -0
  175. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/motor.py +0 -0
  176. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/odin/__init__.py +0 -0
  177. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/odin/_odin_io.py +0 -0
  178. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/pmac/__init__.py +0 -0
  179. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/pmac/_pmac_io.py +0 -0
  180. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/pmac/_pmac_trajectory_generation.py +0 -0
  181. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/pmac/_utils.py +0 -0
  182. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/signal.py +0 -0
  183. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/testing/__init__.py +0 -0
  184. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/testing/_example_ioc.py +0 -0
  185. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/testing/_utils.py +0 -0
  186. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/testing/test_records.db +0 -0
  187. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/epics/testing/test_records_pva.db +0 -0
  188. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/__init__.py +0 -0
  189. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/core.py +0 -0
  190. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/eiger/__init__.py +0 -0
  191. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/eiger/_eiger.py +0 -0
  192. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/eiger/_eiger_controller.py +0 -0
  193. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/jungfrau/__init__.py +0 -0
  194. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/jungfrau/_controller.py +0 -0
  195. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/jungfrau/_jungfrau.py +0 -0
  196. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/jungfrau/_signals.py +0 -0
  197. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/jungfrau/_utils.py +0 -0
  198. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/odin/__init__.py +0 -0
  199. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/__init__.py +0 -0
  200. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_block.py +0 -0
  201. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_hdf_panda.py +0 -0
  202. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_table.py +0 -0
  203. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_trigger.py +0 -0
  204. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/fastcs/panda/_writer.py +0 -0
  205. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/__init__.py +0 -0
  206. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_ensure_connected.py +0 -0
  207. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_fly.py +0 -0
  208. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_nd_attributes.py +0 -0
  209. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_panda.py +0 -0
  210. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_settings.py +0 -0
  211. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_utils.py +0 -0
  212. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/plan_stubs/_wait_for_awaitable.py +0 -0
  213. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/py.typed +0 -0
  214. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/__init__.py +0 -0
  215. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/__main__.py +0 -0
  216. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_blob_detector.py +0 -0
  217. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_blob_detector_controller.py +0 -0
  218. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_blob_detector_writer.py +0 -0
  219. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_mirror_horizontal.py +0 -0
  220. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_mirror_vertical.py +0 -0
  221. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_motor.py +0 -0
  222. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_pattern_generator.py +0 -0
  223. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_point_detector.py +0 -0
  224. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/sim/_stage.py +0 -0
  225. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/__init__.py +0 -0
  226. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/_base_device.py +0 -0
  227. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/_converters.py +0 -0
  228. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/_signal.py +0 -0
  229. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/core/_utils.py +0 -0
  230. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/__init__.py +0 -0
  231. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/_counter.py +0 -0
  232. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/_detector.py +0 -0
  233. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/_mover.py +0 -0
  234. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/_tango/__init__.py +0 -0
  235. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/demo/_tango/_servers.py +0 -0
  236. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/testing/__init__.py +0 -0
  237. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/testing/_one_of_everything.py +0 -0
  238. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/tango/testing/_test_config.py +0 -0
  239. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/__init__.py +0 -0
  240. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/__pytest_assert_rewrite.py +0 -0
  241. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/_assert.py +0 -0
  242. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/_one_of_everything.py +0 -0
  243. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/_single_derived.py +0 -0
  244. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/_utils.py +0 -0
  245. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async/testing/_wait_for_pending.py +0 -0
  246. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async.egg-info/dependency_links.txt +0 -0
  247. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async.egg-info/requires.txt +0 -0
  248. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/src/ophyd_async.egg-info/top_level.txt +0 -0
  249. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/README.md +0 -0
  250. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/conftest.py +0 -0
  251. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/__init__.py +0 -0
  252. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/conftest.py +0 -0
  253. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/adsim/baseline.yaml +0 -0
  254. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/adsim/external_dependencies.sh +0 -0
  255. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/adsim/test_adsim_system.py +0 -0
  256. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/eiger/README.md +0 -0
  257. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/eiger/start_iocs_and_run_tests.sh +0 -0
  258. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/eiger/test_eiger_system.py +0 -0
  259. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/signal/test_signals.py +0 -0
  260. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/signal/test_yaml_save_ca.yaml +0 -0
  261. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/epics/signal/test_yaml_save_pva.yaml +0 -0
  262. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/fastcs/panda/test_panda_connect.py +0 -0
  263. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/system_tests/test_tutorials.py +0 -0
  264. {ophyd_async-0.14.0/tests/system_tests/tango → ophyd_async-0.14.2/tests/system_tests_tango}/context_subprocess.py +0 -0
  265. {ophyd_async-0.14.0/tests/system_tests/tango → ophyd_async-0.14.2/tests/system_tests_tango}/test_base_device.py +0 -0
  266. {ophyd_async-0.14.0/tests/system_tests/tango → ophyd_async-0.14.2/tests/system_tests_tango}/test_tango_transport.py +0 -0
  267. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/__init__.py +0 -0
  268. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_auto_init_devices.py +0 -0
  269. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_detector.py +0 -0
  270. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_flyer.py +0 -0
  271. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_log.py +0 -0
  272. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_mock_signal_backend.py +0 -0
  273. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_protocol.py +0 -0
  274. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_readable.py +0 -0
  275. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_signal.py +0 -0
  276. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_soft_signal_backend.py +0 -0
  277. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_status.py +0 -0
  278. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_subset_enum.py +0 -0
  279. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_table.py +0 -0
  280. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_utils.py +0 -0
  281. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/core/test_watchable_async_status.py +0 -0
  282. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adandor/test_andor.py +0 -0
  283. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adaravis/test_aravis.py +0 -0
  284. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_cont_acq_detector.py +0 -0
  285. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_detectors.py +0 -0
  286. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_drivers.py +0 -0
  287. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_plugins.py +0 -0
  288. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_scans.py +0 -0
  289. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_single_trigger.py +0 -0
  290. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adcore/test_writers.py +0 -0
  291. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adkinetix/test_kinetix.py +0 -0
  292. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adpilatus/test_pilatus.py +0 -0
  293. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/adsimdetector/test_sim.py +0 -0
  294. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/advimba/test_vimba.py +0 -0
  295. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/conftest.py +0 -0
  296. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/demo/test_epics_demo.py +0 -0
  297. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/eiger/test_odin_io.py +0 -0
  298. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pmac/conftest.py +0 -0
  299. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pmac/test_pmac_io.py +0 -0
  300. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pmac/test_pmac_trajectory_generation.py +0 -0
  301. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/pmac/test_pmac_utils.py +0 -0
  302. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/signal/test_common.py +0 -0
  303. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/test_areadetector_subclass_naming.py +0 -0
  304. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/epics/test_motor.py +0 -0
  305. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/eiger/test_eiger_controller.py +0 -0
  306. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/eiger/test_eiger_detector.py +0 -0
  307. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/jungfrau/__init__.py +0 -0
  308. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/jungfrau/test_controller.py +0 -0
  309. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/jungfrau/test_utils.py +0 -0
  310. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/db/panda.db +0 -0
  311. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_hdf_panda.py +0 -0
  312. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_panda_connect_mock.py +0 -0
  313. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_panda_control.py +0 -0
  314. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_panda_utils.py +0 -0
  315. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_seq_table.py +0 -0
  316. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_trigger.py +0 -0
  317. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/fastcs/panda/test_writer.py +0 -0
  318. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/plan_stubs/test_ensure_connected.py +0 -0
  319. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/plan_stubs/test_fly.py +0 -0
  320. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/plan_stubs/test_settings.py +0 -0
  321. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/plan_stubs/test_setup.py +0 -0
  322. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/sim/__init__.py +0 -0
  323. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/sim/test_sim_blob_detector.py +0 -0
  324. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/sim/test_sim_motor.py +0 -0
  325. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/test_branching.py +0 -0
  326. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/test_cli.py +0 -0
  327. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/test_data/test_yaml_config_save.yaml +0 -0
  328. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/tests/unit_tests/test_data/test_yaml_save.yaml +0 -0
  329. {ophyd_async-0.14.0 → ophyd_async-0.14.2}/uv.lock +0 -0
@@ -1,5 +1,5 @@
1
1
  # Changes here will be overwritten by Copier
2
- _commit: 5.0.0a5
2
+ _commit: 5.0.1
3
3
  _src_path: https://github.com/DiamondLightSource/python-copier-template
4
4
  author_email: tom.cobb@diamond.ac.uk
5
5
  author_name: Tom Cobb
@@ -24,4 +24,4 @@ It is recommended that developers use a [vscode devcontainer](https://code.visua
24
24
 
25
25
  This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects.
26
26
 
27
- For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.0a5/how-to.html).
27
+ For more information on common tasks like setting up a developer environment, running the tests, and setting a pre-commit hook, see the template's [How-to guides](https://diamondlightsource.github.io/python-copier-template/5.0.1/how-to.html).
@@ -13,9 +13,6 @@ on:
13
13
  type: string
14
14
  description: The path to look for tests
15
15
  required: true
16
- secrets:
17
- CODECOV_TOKEN:
18
- required: true
19
16
 
20
17
  env:
21
18
  # https://github.com/pytest-dev/pytest/issues/2042
@@ -59,5 +56,3 @@ jobs:
59
56
  with:
60
57
  name: ${{ inputs.python-version }}/${{ inputs.runs-on }}/${{ inputs.tests-path }}
61
58
  files: cov.xml
62
- env:
63
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
@@ -20,14 +20,16 @@ jobs:
20
20
  runs-on: ["ubuntu-latest", "windows-latest"] # can add macos-latest
21
21
  python-version: ["3.11", "3.12", "3.13"]
22
22
  tests-path: ["", "tests/system_tests"]
23
+ include:
24
+ - runs-on: "ubuntu-latest"
25
+ python-version: "3.11"
26
+ tests-path: "tests/system_tests_tango"
23
27
  fail-fast: false
24
28
  uses: ./.github/workflows/_test.yml
25
29
  with:
26
30
  runs-on: ${{ matrix.runs-on }}
27
31
  python-version: ${{ matrix.python-version }}
28
32
  tests-path: ${{ matrix.tests-path }}
29
- secrets:
30
- CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
31
33
 
32
34
  docs:
33
35
  uses: ./.github/workflows/_docs.yml
@@ -0,0 +1,52 @@
1
+ name: Claude PR Comment Review
2
+ # https://github.com/anthropics/claude-code-action/blob/main/docs/solutions.md#automatic-pr-code-review
3
+ # https://skywork.ai/blog/how-to-use-claude-code-for-prs-code-reviews-guide/#step-3-add-a-comment-triggered-workflow-copy-pasteable
4
+
5
+ on:
6
+ issue_comment:
7
+ types: [created]
8
+
9
+ jobs:
10
+ review:
11
+ if: ${{ contains(github.event.comment.body, '@claude') && github.event.issue.pull_request != null }}
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: read
15
+ pull-requests: write
16
+ id-token: write
17
+ steps:
18
+ - uses: actions/checkout@v5
19
+ with:
20
+ fetch-depth: 1
21
+
22
+ - run: find
23
+
24
+ - uses: anthropics/claude-code-action@v1
25
+ with:
26
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
27
+ track_progress: true # ✨ Enables tracking comments
28
+ prompt: |
29
+ REPO: ${{ github.repository }}
30
+ PR NUMBER: ${{ github.event.issue.number }}
31
+
32
+ Please review this pull request with a focus on:
33
+ - Code quality and best practices
34
+ - Potential bugs or issues
35
+ - Security implications
36
+ - Performance considerations
37
+
38
+ Note: The PR branch is already checked out in the current working directory.
39
+
40
+ Make sure to:
41
+ - Use `gh pr comment` for concise top-level feedback
42
+ - Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues
43
+ - Put all detailed feedback and recommendations in inline comments and do not duplicate in the main PR comment
44
+ - Anywhere you have a line number reference, use an inline comment
45
+ - Check structure is consist with existing code style
46
+ - Skip style issues already handled by linters
47
+ - Check for duplication of code already in the repository; aim for re-use where sensible
48
+ - Favour composition over inheritence
49
+ - Respond in concise bullet point form; avoid restating code
50
+
51
+ claude_args: |
52
+ --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"
@@ -3,7 +3,7 @@ repos:
3
3
  rev: v5.0.0
4
4
  hooks:
5
5
  - id: check-added-large-files
6
- args: ["--maxkb=1000"] # uv.lock is more than 500kB
6
+ exclude: ^uv.lock
7
7
  - id: check-yaml
8
8
  - id: check-merge-conflict
9
9
  - id: end-of-file-fixer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.14.0
3
+ Version: 0.14.2
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
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.14.0'
32
- __version_tuple__ = version_tuple = (0, 14, 0)
31
+ __version__ = version = '0.14.2'
32
+ __version_tuple__ = version_tuple = (0, 14, 2)
33
33
 
34
- __commit_id__ = commit_id = 'g3da44d6fb'
34
+ __commit_id__ = commit_id = 'ga221add53'
@@ -48,6 +48,7 @@ from ._protocol import AsyncConfigurable, AsyncReadable, AsyncStageable, Watcher
48
48
  from ._providers import (
49
49
  AutoIncrementFilenameProvider,
50
50
  AutoIncrementingPathProvider,
51
+ AutoMaxIncrementingPathProvider,
51
52
  DatasetDescriber,
52
53
  FilenameProvider,
53
54
  PathInfo,
@@ -222,6 +223,7 @@ __all__ = [
222
223
  "FilenameProvider",
223
224
  "StaticFilenameProvider",
224
225
  "AutoIncrementFilenameProvider",
226
+ "AutoMaxIncrementingPathProvider",
225
227
  "UUIDFilenameProvider",
226
228
  # Datatset
227
229
  "DatasetDescriber",
@@ -1,5 +1,15 @@
1
- from collections.abc import Awaitable, Callable
2
- from typing import Any, Generic, get_args, get_origin, get_type_hints, is_typeddict
1
+ import functools
2
+ from collections.abc import Awaitable, Callable, Mapping
3
+ from inspect import Parameter, signature
4
+ from typing import (
5
+ Any,
6
+ Generic,
7
+ TypeVar,
8
+ get_args,
9
+ get_origin,
10
+ get_type_hints,
11
+ is_typeddict,
12
+ )
3
13
 
4
14
  from bluesky.protocols import Locatable
5
15
 
@@ -53,12 +63,13 @@ class DerivedSignalFactory(Generic[TransformT]):
53
63
  # Populate expected parameters and types
54
64
  expected = {
55
65
  **{k: f.annotation for k, f in transform_cls.model_fields.items()},
56
- **{
57
- k: v
58
- for k, v in get_type_hints(transform_cls.raw_to_derived).items()
59
- if k not in {"self", "return"}
60
- },
66
+ **_get_params_types_dict(transform_cls.raw_to_derived),
61
67
  }
68
+ if empty_keys := [k for k, v in expected.items() if v == Parameter.empty]:
69
+ raise TypeError(
70
+ f"{transform_cls.raw_to_derived} is missing a type "
71
+ f"hint for arguments: {empty_keys}"
72
+ )
62
73
 
63
74
  # Populate received parameters and types
64
75
  # Use Primitive's type, Signal's datatype,
@@ -76,7 +87,19 @@ class DerivedSignalFactory(Generic[TransformT]):
76
87
  f"Expected the following to be passed as keyword arguments "
77
88
  f"{expected}, got {received}"
78
89
  )
79
- raise TypeError(msg)
90
+ if set(expected.keys()) - set(received.keys()):
91
+ raise TypeError(msg)
92
+
93
+ for k in set(expected.keys()):
94
+ if isinstance(expected[k], type):
95
+ if not issubclass(received[k], expected[k]):
96
+ raise TypeError(msg)
97
+ elif isinstance(expected[k], TypeVar):
98
+ bound = expected[k].__bound__
99
+ if isinstance(bound, type) and not issubclass(
100
+ received[k], bound
101
+ ):
102
+ raise TypeError(msg)
80
103
  self._set_derived_takes_dict = (
81
104
  is_typeddict(_get_first_arg_datatype(set_derived)) if set_derived else False
82
105
  )
@@ -195,28 +218,28 @@ def _get_return_datatype(func: Callable[..., SignalDatatypeT]) -> type[SignalDat
195
218
  def _get_first_arg_datatype(
196
219
  func: Callable[[SignalDatatypeT], Any],
197
220
  ) -> type[SignalDatatypeT]:
198
- args = get_type_hints(func)
199
- args.pop("return", None)
221
+ args = _get_params_types_dict(func)
200
222
  if not args:
201
223
  msg = f"{func} does not have a type hinted argument"
202
224
  raise TypeError(msg)
203
225
  return list(args.values())[0]
204
226
 
205
227
 
228
+ def _get_params_types_dict(inspected_function: Callable) -> Mapping[str, Any]:
229
+ sig = signature(inspected_function, eval_str=True)
230
+ exclude_keys = {"self", "args", "kwargs", "cls"}
231
+ return {k: v.annotation for k, v in sig.parameters.items() if k not in exclude_keys}
232
+
233
+
206
234
  def _make_factory(
207
- raw_to_derived: Callable[..., SignalDatatypeT] | None = None,
235
+ raw_to_derived_func: Callable[..., SignalDatatypeT] | None = None,
208
236
  set_derived: Callable[[SignalDatatypeT], Awaitable[None]] | None = None,
209
237
  raw_devices_and_constants: dict[str, Device | Primitive] | None = None,
210
238
  ) -> DerivedSignalFactory:
211
- if raw_to_derived:
239
+ if raw_to_derived_func:
212
240
 
213
241
  class DerivedTransform(Transform):
214
- def raw_to_derived(self, **kwargs) -> dict[str, SignalDatatypeT]:
215
- return {"value": raw_to_derived(**kwargs)}
216
-
217
- # Update the signature for raw_to_derived to match what we are passed as this
218
- # will be checked in DerivedSignalFactory
219
- DerivedTransform.raw_to_derived.__annotations__ = get_type_hints(raw_to_derived)
242
+ raw_to_derived = _dict_wrapper(raw_to_derived_func)
220
243
 
221
244
  return DerivedSignalFactory(
222
245
  DerivedTransform,
@@ -245,7 +268,7 @@ def derived_signal_r(
245
268
  The names of these arguments must match the arguments of raw_to_derived.
246
269
  """
247
270
  factory = _make_factory(
248
- raw_to_derived=raw_to_derived,
271
+ raw_to_derived_func=raw_to_derived,
249
272
  raw_devices_and_constants=raw_devices_and_constants,
250
273
  )
251
274
  return factory.derived_signal_r(
@@ -278,16 +301,16 @@ def derived_signal_rw(
278
301
  The names of these arguments must match the arguments of raw_to_derived.
279
302
  """
280
303
  raw_to_derived_datatype = _get_return_datatype(raw_to_derived)
281
- set_derived_datatype = _get_first_arg_datatype(set_derived)
282
- if raw_to_derived_datatype != set_derived_datatype:
304
+ set_derived_arg_datatype = _get_first_arg_datatype(set_derived)
305
+ if raw_to_derived_datatype != set_derived_arg_datatype:
283
306
  msg = (
284
307
  f"{raw_to_derived} has datatype {raw_to_derived_datatype} "
285
- f"!= {set_derived_datatype} datatype {set_derived_datatype}"
308
+ f"!= {set_derived_arg_datatype} datatype {set_derived_arg_datatype}"
286
309
  )
287
310
  raise TypeError(msg)
288
311
 
289
312
  factory = _make_factory(
290
- raw_to_derived=raw_to_derived,
313
+ raw_to_derived_func=raw_to_derived,
291
314
  set_derived=set_derived,
292
315
  raw_devices_and_constants=raw_devices_and_constants,
293
316
  )
@@ -343,3 +366,13 @@ def _partition_by_keys(data: dict, keys: set) -> tuple[dict, dict]:
343
366
  else:
344
367
  group_excluded[k] = v
345
368
  return group_excluded, group_included
369
+
370
+
371
+ def _dict_wrapper(
372
+ fn: Callable[..., SignalDatatypeT],
373
+ ) -> Callable[..., dict[str, SignalDatatypeT]]:
374
+ @functools.wraps(fn)
375
+ def wrapped(self, **kwargs):
376
+ return {"value": fn(**kwargs)}
377
+
378
+ return wrapped
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import types
3
4
  from abc import abstractmethod
4
5
  from collections.abc import Callable, Iterator, Sequence
5
6
  from typing import (
@@ -9,8 +10,10 @@ from typing import (
9
10
  NoReturn,
10
11
  Protocol,
11
12
  TypeVar,
13
+ Union,
12
14
  cast,
13
15
  get_args,
16
+ get_origin,
14
17
  get_type_hints,
15
18
  runtime_checkable,
16
19
  )
@@ -76,6 +79,7 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
76
79
  self._extras: dict[UniqueName, Sequence[Any]] = {}
77
80
  self._signal_datatype: dict[LogicalName, type | None] = {}
78
81
  self._vector_device_type: dict[LogicalName, type[Device] | None] = {}
82
+ self._optional_devices: set[str] = set()
79
83
  self.ignored_signals: set[str] = set()
80
84
  # Backends and Connectors stored ready for the connection phase
81
85
  self._unfilled_backends: dict[
@@ -121,6 +125,20 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
121
125
  self.ignored_signals.add(attr_name)
122
126
  name = UniqueName(attr_name)
123
127
  origin = get_origin_class(annotation)
128
+ args = get_args(annotation)
129
+
130
+ if (
131
+ get_origin(annotation) is Union
132
+ and types.NoneType in args
133
+ and len(args) == 2
134
+ ):
135
+ # Annotation is an Union with two arguments, one of which is None
136
+ # Make this signal an optional parameter and set origin to T
137
+ # so the device is added to unfilled_connectors
138
+ self._optional_devices.add(name)
139
+ (annotation,) = [x for x in args if x is not types.NoneType]
140
+ origin = get_origin_class(annotation)
141
+
124
142
  if (
125
143
  name == "parent"
126
144
  or name.startswith("_")
@@ -241,10 +259,17 @@ class DeviceFiller(Generic[SignalBackendT, DeviceConnectorT]):
241
259
  :param source: The source of the data that should have done the filling, for
242
260
  reporting as an error message
243
261
  """
244
- unfilled = sorted(set(self._unfilled_connectors).union(self._unfilled_backends))
245
- if unfilled:
262
+ unfilled = set(self._unfilled_connectors).union(self._unfilled_backends)
263
+ unfilled_optional = sorted(unfilled.intersection(self._optional_devices))
264
+
265
+ for name in unfilled_optional:
266
+ setattr(self._device, name, None)
267
+
268
+ required = sorted(unfilled.difference(unfilled_optional))
269
+
270
+ if required:
246
271
  raise RuntimeError(
247
- f"{self._device.name}: cannot provision {unfilled} from {source}"
272
+ f"{self._device.name}: cannot provision {required} from {source}"
248
273
  )
249
274
 
250
275
  def _ensure_device_vector(self, name: LogicalName) -> DeviceVector:
@@ -1,9 +1,10 @@
1
+ import re
1
2
  import uuid
2
3
  from abc import abstractmethod
3
4
  from collections.abc import Callable
4
5
  from dataclasses import dataclass
5
6
  from datetime import date
6
- from pathlib import PurePath, PureWindowsPath
7
+ from pathlib import Path, PurePath, PureWindowsPath
7
8
  from typing import Protocol
8
9
  from urllib.parse import urlunparse
9
10
 
@@ -157,6 +158,98 @@ class StaticPathProvider(PathProvider):
157
158
  )
158
159
 
159
160
 
161
+ class AutoMaxIncrementingPathProvider(PathProvider):
162
+ """Increment directory name on each call by checking existing directories.
163
+
164
+ Looks through directories in a specified base path to increment directory name.
165
+ PathInfo gives path like base_path/0001_dirname/dirname, or
166
+ base_path/yyyy-mm-dd/0001_dirname/dirname if dated is true. Here,
167
+ the '0001' is the value which gets incremented if the file exists already.
168
+
169
+ It's recommended for the base path provider to be non-incrementing.
170
+
171
+ Args:
172
+ base_path_provider: Path to create directories inside of. Note that the filename of
173
+ this provider is used as the top level directory and the filename
174
+ max_digits: Number of digits to pad onto the parent directory.
175
+ starting_value: Number to start incrementing from.
176
+ dated: Whether to create an extra directory to specify the day.
177
+
178
+ """
179
+
180
+ def __init__(
181
+ self,
182
+ base_path_provider: PathProvider,
183
+ max_digits: int = 4,
184
+ starting_value: int = 0,
185
+ dated: bool = False,
186
+ ):
187
+ self._base_path_provider = base_path_provider
188
+ self._max_digits = max_digits
189
+ self._next_value = starting_value
190
+ self._dated = dated
191
+
192
+ def _get_highest_number_from(self, path: Path) -> int:
193
+ # Look through directories in path which end in "_{number} and get highest
194
+ # number"
195
+ highest_number = 0
196
+ candidates = [
197
+ x for x in path.iterdir() if x.is_dir() and re.match(r"^\d+_", x.name)
198
+ ]
199
+ if candidates:
200
+ highest_number = max(
201
+ int(x.name.split("_", maxsplit=1)[0]) for x in candidates
202
+ )
203
+ else:
204
+ highest_number = self._next_value
205
+ return highest_number
206
+
207
+ def __call__(self, device_name: str | None = None) -> PathInfo:
208
+ base_path_info = self._base_path_provider.__call__()
209
+ base_path_dir = Path(base_path_info.directory_path)
210
+ if self._dated:
211
+ # Make sure we are the max ID of any other days to keep numbering
212
+ # consistent.
213
+ cands = [
214
+ self._get_highest_number_from(x)
215
+ for x in base_path_dir.iterdir()
216
+ if re.match(r"^\d\d\d\d-\d\d-\d\d$", x.name)
217
+ ]
218
+ if cands:
219
+ self._next_value = max(max(cands) + 1, self._next_value)
220
+
221
+ path = base_path_dir / date.today().strftime("%Y-%m-%d")
222
+ else:
223
+ path = base_path_dir
224
+
225
+ val_to_use = self._next_value
226
+
227
+ # Get the highest number using files in path, or use
228
+ # stored next value if no files are found.
229
+ if path.exists():
230
+ highest_number = self._get_highest_number_from(path)
231
+ val_to_use = (
232
+ highest_number + 1
233
+ if not highest_number == self._next_value
234
+ else highest_number
235
+ )
236
+
237
+ self._next_value = val_to_use + 1
238
+
239
+ filename = base_path_info.filename
240
+
241
+ padded_counter = f"{val_to_use:0{self._max_digits}}"
242
+ full_path = (
243
+ path / f"{padded_counter}_{filename.strip('_')}" / filename.rstrip("_")
244
+ )
245
+ return PathInfo(
246
+ directory_path=full_path.parent,
247
+ directory_uri=None,
248
+ filename=full_path.name,
249
+ create_dir_depth=0,
250
+ )
251
+
252
+
160
253
  class AutoIncrementingPathProvider(PathProvider):
161
254
  """Provides a new numerically incremented path on each call."""
162
255
 
@@ -10,6 +10,7 @@ from ophyd_async.core import (
10
10
  AsyncStatus,
11
11
  FlyerController,
12
12
  error_if_none,
13
+ gather_dict,
13
14
  observe_value,
14
15
  set_and_wait_for_value,
15
16
  wait_for_value,
@@ -202,12 +203,25 @@ class PmacTrajectoryTriggerLogic(FlyerController):
202
203
  coord = self.pmac.coord[motor_info.cs_number]
203
204
  coros = []
204
205
  await coord.defer_moves.set(True)
206
+
207
+ motor_readbacks = await gather_dict(
208
+ {motor: motor.user_readback.get_value() for motor in ramp_up_position}
209
+ )
210
+
211
+ move_times = [
212
+ abs(position - motor_readbacks[motor])
213
+ / motor_info.motor_max_velocity[motor]
214
+ for motor, position in ramp_up_position.items()
215
+ ]
216
+
217
+ longest_time = max(move_times)
218
+
205
219
  for motor, position in ramp_up_position.items():
206
220
  coros.append(
207
221
  set_and_wait_for_value(
208
222
  coord.cs_axis_setpoint[motor_info.motor_cs_index[motor]],
209
223
  position,
210
- set_timeout=10,
224
+ set_timeout=longest_time + DEFAULT_TIMEOUT,
211
225
  wait_for_set_completion=False,
212
226
  )
213
227
  )
@@ -29,7 +29,7 @@ class EigerDetectorIO(Device):
29
29
  frame_time: SignalRW[float]
30
30
  nimages: SignalRW[int]
31
31
  ntrigger: SignalRW[int]
32
- nexpi: SignalRW[int]
32
+ nexpi: SignalRW[int] | None
33
33
  trigger_mode: SignalRW[str]
34
34
  roi_mode: SignalRW[str]
35
35
  photon_energy: SignalRW[float]
@@ -35,7 +35,8 @@ class PandaPcapController(DetectorController):
35
35
  await wait_for_value(self.pcap.active, True, timeout=1)
36
36
 
37
37
  async def wait_for_idle(self):
38
- pass
38
+ if self._arm_status and not self._arm_status.done:
39
+ await self._arm_status
39
40
 
40
41
  async def disarm(self):
41
42
  await self.pcap.arm.set(False)
@@ -9,7 +9,9 @@ from ._signal import (
9
9
  tango_signal_x,
10
10
  )
11
11
  from ._tango_transport import (
12
+ AttributeInfoEx,
12
13
  AttributeProxy,
14
+ CommandInfo,
13
15
  CommandProxy,
14
16
  CommandProxyReadCharacter,
15
17
  TangoDoubleStringTable,
@@ -21,6 +23,7 @@ from ._tango_transport import (
21
23
  get_python_type,
22
24
  get_source_metadata,
23
25
  get_tango_trl,
26
+ parse_precision,
24
27
  )
25
28
  from ._utils import (
26
29
  DevStateEnum,
@@ -30,7 +33,9 @@ from ._utils import (
30
33
  )
31
34
 
32
35
  __all__ = [
36
+ "AttributeInfoEx",
33
37
  "AttributeProxy",
38
+ "CommandInfo",
34
39
  "CommandProxy",
35
40
  "CommandProxyReadCharacter",
36
41
  "DevStateEnum",
@@ -44,6 +49,7 @@ __all__ = [
44
49
  "infer_python_type",
45
50
  "infer_signal_type",
46
51
  "make_backend",
52
+ "parse_precision",
47
53
  "tango_signal_r",
48
54
  "tango_signal_rw",
49
55
  "tango_signal_w",
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import functools
3
3
  import logging
4
+ import re
4
5
  import time
5
6
  from abc import abstractmethod
6
7
  from collections.abc import Callable, Coroutine, Sequence
@@ -582,6 +583,15 @@ class CommandProxy(TangoProxy):
582
583
  pass
583
584
 
584
585
 
586
+ PRECISION_PATTERN = re.compile(r"%\d*\.(\d+)f")
587
+
588
+
589
+ def parse_precision(config: AttributeInfoEx):
590
+ if config.format and (matches := PRECISION_PATTERN.findall(config.format)):
591
+ return int(matches[0])
592
+ return None
593
+
594
+
585
595
  def get_dtype_extended(datatype) -> object | None:
586
596
  """For converting tango types to numpy datatype formats."""
587
597
  # DevState tango type does not have numpy equivalents
@@ -639,17 +649,8 @@ def get_source_metadata(
639
649
  if tr_dtype == CmdArgType.DevState:
640
650
  _choices = list(DevState.names.keys())
641
651
 
642
- _precision = None
643
- if config.format:
644
- try:
645
- _precision = int(config.format.split(".")[1].split("f")[0])
646
- except (ValueError, IndexError) as exc:
647
- # If parsing config.format fails, _precision remains None.
648
- logger.warning(
649
- "Failed to parse precision from config.format: %s. Error: %s",
650
- config.format,
651
- exc,
652
- )
652
+ _precision = parse_precision(config)
653
+
653
654
  no_limits = Limits(
654
655
  control=LimitsRange(high=None, low=None),
655
656
  warning=LimitsRange(high=None, low=None),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ophyd-async
3
- Version: 0.14.0
3
+ Version: 0.14.2
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
@@ -28,6 +28,7 @@ uv.lock
28
28
  .github/workflows/_test.yml
29
29
  .github/workflows/_tox.yml
30
30
  .github/workflows/ci.yml
31
+ .github/workflows/claude.yml
31
32
  .github/workflows/periodic.yml
32
33
  docs/conf.py
33
34
  docs/explanations.md
@@ -250,11 +251,11 @@ tests/system_tests/epics/signal/test_signals.py
250
251
  tests/system_tests/epics/signal/test_yaml_save_ca.yaml
251
252
  tests/system_tests/epics/signal/test_yaml_save_pva.yaml
252
253
  tests/system_tests/fastcs/panda/test_panda_connect.py
253
- tests/system_tests/tango/conftest.py
254
- tests/system_tests/tango/context_subprocess.py
255
- tests/system_tests/tango/test_base_device.py
256
- tests/system_tests/tango/test_tango_signals.py
257
- tests/system_tests/tango/test_tango_transport.py
254
+ tests/system_tests_tango/conftest.py
255
+ tests/system_tests_tango/context_subprocess.py
256
+ tests/system_tests_tango/test_base_device.py
257
+ tests/system_tests_tango/test_tango_signals.py
258
+ tests/system_tests_tango/test_tango_transport.py
258
259
  tests/unit_tests/__init__.py
259
260
  tests/unit_tests/test_branching.py
260
261
  tests/unit_tests/test_cli.py