bec-server 4.2.0__tar.gz → 4.3.0__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 (211) hide show
  1. {bec_server-4.2.0 → bec_server-4.3.0}/PKG-INFO +1 -1
  2. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/device_server.py +6 -6
  3. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_manager.py +4 -0
  4. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/fermat_scan.py +12 -2
  5. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/grid_scan.py +4 -1
  6. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/hexagonal_scan.py +10 -1
  7. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/line_scan.py +4 -1
  8. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/log_scan.py +4 -1
  9. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/multi_region_grid_scan.py +4 -1
  10. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/multi_region_line_scan.py +4 -1
  11. bec_server-4.3.0/bec_server/scan_server/scans/path_optimization.py +5 -0
  12. bec_server-4.3.0/bec_server/scan_server/scans/position_generators.py +33 -0
  13. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/round_roi_scan.py +13 -1
  14. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/round_scan.py +11 -1
  15. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_base.py +12 -1
  16. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_components.py +2 -2
  17. {bec_server-4.2.0 → bec_server-4.3.0}/pyproject.toml +1 -1
  18. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_device_server.py +60 -0
  19. bec_server-4.3.0/tests/tests_scan_server/scans/test_position_preview.py +61 -0
  20. bec_server-4.3.0/tests/tests_scan_server/test_path_optimization.py +14 -0
  21. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_server_scan_manager.py +11 -0
  22. bec_server-4.2.0/bec_server/scan_server/scans/path_optimization.py +0 -503
  23. bec_server-4.2.0/bec_server/scan_server/scans/position_generators.py +0 -565
  24. bec_server-4.2.0/tests/tests_scan_server/scans/test_position_generators.py +0 -212
  25. bec_server-4.2.0/tests/tests_scan_server/test_path_optimization.py +0 -276
  26. {bec_server-4.2.0 → bec_server-4.3.0}/.gitignore +0 -0
  27. {bec_server-4.2.0 → bec_server-4.3.0}/.zed/debug.json +0 -0
  28. {bec_server-4.2.0 → bec_server-4.3.0}/README.md +0 -0
  29. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/__init__.py +0 -0
  30. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/__init__.py +0 -0
  31. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/actor.py +0 -0
  32. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/builtin_actor_manager.py +0 -0
  33. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/manager.py +0 -0
  34. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/scan_interlock.py +0 -0
  35. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/actors/worker.py +0 -0
  36. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/bec_server_utils/__init__.py +0 -0
  37. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/bec_server_utils/launch.py +0 -0
  38. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/bec_server_utils/service_handler.py +0 -0
  39. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/bec_server_utils/subprocess_launch.py +0 -0
  40. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/bec_server_utils/tmux_launch.py +0 -0
  41. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/__init__.py +0 -0
  42. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/cli/__init__.py +0 -0
  43. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/cli/launch.py +0 -0
  44. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/dap_server.py +0 -0
  45. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/dap_service.py +0 -0
  46. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/dap_service_manager.py +0 -0
  47. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/data_processing/lmfit1d_service.py +0 -0
  48. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/__init__.py +0 -0
  49. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/bec_message_handler.py +0 -0
  50. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/cli/__init__.py +0 -0
  51. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/cli/launch.py +0 -0
  52. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/devices/__init__.py +0 -0
  53. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/devices/config_update_handler.py +0 -0
  54. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/devices/device_serializer.py +0 -0
  55. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/devices/devicemanager.py +0 -0
  56. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/friendly_device_exceptions.py +0 -0
  57. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/ophyd_callback_monitor.py +0 -0
  58. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/rpc_handler.py +0 -0
  59. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/tests/__init__.py +0 -0
  60. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/device_server/tests/utils.py +0 -0
  61. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/__init__.py +0 -0
  62. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/async_writer.py +0 -0
  63. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/cli/__init__.py +0 -0
  64. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/cli/launch.py +0 -0
  65. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/default_writer.py +0 -0
  66. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/file_writer.py +0 -0
  67. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/file_writer_manager.py +0 -0
  68. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/file_writer/merged_dicts.py +0 -0
  69. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/Containerfile.bec_linux_base +0 -0
  70. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/Containerfile.requirements +0 -0
  71. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/Containerfile.worker +0 -0
  72. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/__init__.py +0 -0
  73. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/_dev_runner.py +0 -0
  74. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/builtin_procedures.py +0 -0
  75. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/constants.py +0 -0
  76. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/container_utils.py +0 -0
  77. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/container_worker.py +0 -0
  78. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/manager.py +0 -0
  79. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/oop_worker_base.py +0 -0
  80. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/procedure_registry.py +0 -0
  81. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/protocol.py +0 -0
  82. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/subprocess_worker.py +0 -0
  83. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/procedures/worker_base.py +0 -0
  84. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/__init__.py +0 -0
  85. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/bec_emitter.py +0 -0
  86. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/cli/__init__.py +0 -0
  87. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/cli/launch.py +0 -0
  88. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/emitter.py +0 -0
  89. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_bundler/scan_bundler.py +0 -0
  90. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/__init__.py +0 -0
  91. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/beamline_state_manager.py +0 -0
  92. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/cli/__init__.py +0 -0
  93. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/cli/launch.py +0 -0
  94. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/device_lock_registry.py +0 -0
  95. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/direct_scan_worker.py +0 -0
  96. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/errors.py +0 -0
  97. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/instruction_handler.py +0 -0
  98. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_assembler.py +0 -0
  99. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_guard.py +0 -0
  100. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_queue.py +0 -0
  101. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_server.py +0 -0
  102. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scan_worker.py +0 -0
  103. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/__init__.py +0 -0
  104. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/acquire.py +0 -0
  105. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/cont_line_scan.py +0 -0
  106. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/device_rpc.py +0 -0
  107. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/line_sweep_scan.py +0 -0
  108. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/list_scan.py +0 -0
  109. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/move.py +0 -0
  110. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_actions.py +0 -0
  111. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_argument_modifier.py +0 -0
  112. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_modifier.py +0 -0
  113. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/scan_status.py +0 -0
  114. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/time_scan.py +0 -0
  115. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/scans/updated_move.py +0 -0
  116. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/tests/__init__.py +0 -0
  117. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/tests/fixtures.py +0 -0
  118. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/tests/scan_fixtures.py +0 -0
  119. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/tests/scan_hook_tests.py +0 -0
  120. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scan_server/tests/utils.py +0 -0
  121. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/__init__.py +0 -0
  122. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/__init__.py +0 -0
  123. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/atlas_active_client_emitter.py +0 -0
  124. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/atlas_connector.py +0 -0
  125. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/atlas_forwarder.py +0 -0
  126. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/atlas_metadata_handler.py +0 -0
  127. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/atlas_plugin_repo_emitter.py +0 -0
  128. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/atlas/config_handler.py +0 -0
  129. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/cli/__init__.py +0 -0
  130. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/cli/launch.py +0 -0
  131. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/scihub.py +0 -0
  132. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/service_handler/__init__.py +0 -0
  133. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/scihub/service_handler/service_handler.py +0 -0
  134. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/test/__init__.py +0 -0
  135. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/test/actor_test_utils.py +0 -0
  136. {bec_server-4.2.0 → bec_server-4.3.0}/bec_server/test/helpers.py +0 -0
  137. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_actors/test_actors.py +0 -0
  138. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_bec_server_utils/test_main.py +0 -0
  139. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_bec_server_utils/test_service_handler.py +0 -0
  140. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_bec_server_utils/test_subprocess_launch.py +0 -0
  141. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_bec_server_utils/test_tmux_launch.py +0 -0
  142. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_data_processing/conftest.py +0 -0
  143. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_data_processing/test_dap_cli_launch.py +0 -0
  144. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_data_processing/test_dap_server.py +0 -0
  145. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_data_processing/test_dap_service_manager.py +0 -0
  146. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_data_processing/test_lmfit1d_service.py +0 -0
  147. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/conftest.py +0 -0
  148. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_config_handler.py +0 -0
  149. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_device_instructions.py +0 -0
  150. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_device_manager_ds.py +0 -0
  151. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_device_serializer.py +0 -0
  152. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_device_server_cli_launch.py +0 -0
  153. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_ophyd_callback_monitor.py +0 -0
  154. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_device_server/test_rpc_handler.py +0 -0
  155. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_file_writer/conftest.py +0 -0
  156. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_file_writer/test_async_file_writer.py +0 -0
  157. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_file_writer/test_file_writer.py +0 -0
  158. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_file_writer/test_file_writer_cli_launch.py +0 -0
  159. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_file_writer/test_file_writer_manager.py +0 -0
  160. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_bundler/conftest.py +0 -0
  161. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_bundler/test_bec_emitter.py +0 -0
  162. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_bundler/test_scan_bundler.py +0 -0
  163. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_bundler/test_scan_bundler_cli_launch.py +0 -0
  164. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/conftest.py +0 -0
  165. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/__init__.py +0 -0
  166. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_acquire.py +0 -0
  167. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_cont_line_scan.py +0 -0
  168. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_device_rpc_scan.py +0 -0
  169. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_fermat_scan.py +0 -0
  170. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_grid_scan.py +0 -0
  171. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_hexagonal_scan.py +0 -0
  172. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_line_scan.py +0 -0
  173. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_line_sweep_scan.py +0 -0
  174. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_list_scan.py +0 -0
  175. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_log_scan.py +0 -0
  176. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_move_scan.py +0 -0
  177. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_multi_region_grid_scan.py +0 -0
  178. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_multi_region_line_scan.py +0 -0
  179. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_relative_scan_return_to_start.py +0 -0
  180. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_round_roi_scan.py +0 -0
  181. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_round_scan.py +0 -0
  182. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_scan_actions.py +0 -0
  183. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_scan_components.py +0 -0
  184. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_scan_status.py +0 -0
  185. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_time_scan.py +0 -0
  186. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/scans/test_updated_move_scan.py +0 -0
  187. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_beamline_state_manager.py +0 -0
  188. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_builtin_actor_manager.py +0 -0
  189. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_container_utils.py +0 -0
  190. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_device_lock_registry.py +0 -0
  191. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_direct_scan_worker.py +0 -0
  192. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_instruction_handler.py +0 -0
  193. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_procedure_container_worker.py +0 -0
  194. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_procedures.py +0 -0
  195. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_argument_modifier.py +0 -0
  196. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_assembler.py +0 -0
  197. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_fixture_imports.py +0 -0
  198. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_guard.py +0 -0
  199. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_interlock.py +0 -0
  200. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_modifier.py +0 -0
  201. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_server_cli_launch.py +0 -0
  202. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_server_queue.py +0 -0
  203. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scan_server/test_scan_worker.py +0 -0
  204. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/conftest.py +0 -0
  205. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_active_client_emitter.py +0 -0
  206. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_config_handler.py +0 -0
  207. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_connector.py +0 -0
  208. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_forwarder.py +0 -0
  209. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_metadata_handler.py +0 -0
  210. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_atlas_plugin_repo_emitter.py +0 -0
  211. {bec_server-4.2.0 → bec_server-4.3.0}/tests/tests_scihub/test_scihub_cli_launch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: bec-server
3
- Version: 4.2.0
3
+ Version: 4.3.0
4
4
  Summary: BEC server
5
5
  Project-URL: Bug Tracker, https://github.com/bec-project/bec/issues
6
6
  Project-URL: Homepage, https://github.com/bec-project/bec
@@ -832,13 +832,13 @@ class DeviceServer(BECService):
832
832
 
833
833
  def status_callback(self, status):
834
834
  pipe = self.connector.pipeline()
835
- obj = None
836
- if hasattr(status, "device"):
837
- obj = status.device
838
- elif hasattr(status, "obj"):
839
- obj = status.obj
835
+ # BEC records the requested target, which may differ from the device
836
+ # owning a status returned by a delegated operation.
837
+ obj = status.__dict__.get("obj_ref")
840
838
  if obj is None:
841
- obj = status.__dict__.get("obj_ref", None)
839
+ obj = getattr(status, "device", None)
840
+ if obj is None:
841
+ obj = getattr(status, "obj", None)
842
842
 
843
843
  # if we've started a subscription, we need to unsubscribe now
844
844
  # this is typically the case for operations on nested devices.
@@ -164,6 +164,10 @@ class ScanManager:
164
164
  "doc": scan_doc_with_modifiers(scan_cls),
165
165
  "signature": scan_signature_with_modifiers(scan_cls),
166
166
  "gui_visibility": gui_visibility,
167
+ "position_preview": getattr(scan_cls, "position_preview", None),
168
+ "position_preview_parameter_mapping": getattr(
169
+ scan_cls, "position_preview_parameter_mapping", {}
170
+ ),
167
171
  }
168
172
 
169
173
  @staticmethod
@@ -20,11 +20,11 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.logger import bec_logger
26
+ from bec_lib.position_generators import Direction
25
27
  from bec_lib.scan_args import DefaultArgType, ScanArgument, Units
26
- from bec_server.scan_server.scans import position_generators
27
- from bec_server.scan_server.scans.position_generators import Direction
28
28
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
29
29
  from bec_server.scan_server.scans.scan_modifier import scan_hook
30
30
 
@@ -59,6 +59,16 @@ class FermatSpiralScan(ScanBase):
59
59
  ],
60
60
  }
61
61
 
62
+ position_preview = "bec_lib.position_generators.fermat_spiral_pos"
63
+ position_preview_parameter_mapping = {
64
+ "m1_start": "start_motor1",
65
+ "m1_stop": "stop_motor1",
66
+ "m2_start": "start_motor2",
67
+ "m2_stop": "stop_motor2",
68
+ "step": "step",
69
+ "spiral_type": "spiral_type",
70
+ }
71
+
62
72
  def __init__(
63
73
  self,
64
74
  motor1: DeviceBase,
@@ -20,10 +20,10 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.logger import bec_logger
25
26
  from bec_lib.scan_args import DefaultArgType, ScanArgument
26
- from bec_server.scan_server.scans import position_generators
27
27
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType, bundle_args
28
28
  from bec_server.scan_server.scans.scan_modifier import scan_hook
29
29
 
@@ -69,6 +69,9 @@ class GridScan(ScanBase):
69
69
  ],
70
70
  }
71
71
 
72
+ position_preview = "bec_lib.position_generators.nd_grid_positions"
73
+ position_preview_parameter_mapping = {"axes": {"bundle": [1, 2, 3]}, "snaked": "snaked"}
74
+
72
75
  def __init__(
73
76
  self,
74
77
  *args,
@@ -20,9 +20,9 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.scan_args import DefaultArgType, ScanArgument
25
- from bec_server.scan_server.scans import position_generators
26
26
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
27
27
  from bec_server.scan_server.scans.scan_modifier import scan_hook
28
28
 
@@ -53,6 +53,15 @@ class HexagonalScan(ScanBase):
53
53
  ],
54
54
  }
55
55
 
56
+ position_preview = "bec_lib.position_generators.hex_grid_2d"
57
+ position_preview_parameter_mapping = {
58
+ "axes": [
59
+ ["start_motor1", "stop_motor1", "step_motor1"],
60
+ ["start_motor2", "stop_motor2", "step_motor2"],
61
+ ],
62
+ "snaked": "snaked",
63
+ }
64
+
56
65
  def __init__(
57
66
  self,
58
67
  motor1: DeviceBase,
@@ -20,9 +20,9 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.scan_args import DefaultArgType, ScanArgument
25
- from bec_server.scan_server.scans import position_generators
26
26
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType, bundle_args
27
27
  from bec_server.scan_server.scans.scan_modifier import scan_hook
28
28
 
@@ -64,6 +64,9 @@ class LineScan(ScanBase):
64
64
  ],
65
65
  }
66
66
 
67
+ position_preview = "bec_lib.position_generators.line_scan_positions"
68
+ position_preview_parameter_mapping = {"axes": {"bundle": [1, 2]}, "steps": "steps"}
69
+
67
70
  def __init__(
68
71
  self,
69
72
  *args,
@@ -20,9 +20,9 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.scan_args import DefaultArgType, ScanArgument
25
- from bec_server.scan_server.scans import position_generators
26
26
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType, bundle_args
27
27
  from bec_server.scan_server.scans.scan_modifier import scan_hook
28
28
 
@@ -64,6 +64,9 @@ class LogScan(ScanBase):
64
64
  ],
65
65
  }
66
66
 
67
+ position_preview = "bec_lib.position_generators.log_scan_positions"
68
+ position_preview_parameter_mapping = {"axes": {"bundle": [1, 2]}, "steps": "steps"}
69
+
67
70
  def __init__(
68
71
  self,
69
72
  *args,
@@ -18,9 +18,9 @@ from __future__ import annotations
18
18
 
19
19
  import numpy as np
20
20
 
21
+ from bec_lib import position_generators
21
22
  from bec_lib.device import DeviceBase
22
23
  from bec_lib.scan_args import DefaultArgType
23
- from bec_server.scan_server.scans import position_generators
24
24
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
25
25
  from bec_server.scan_server.scans.scan_modifier import scan_hook
26
26
 
@@ -44,6 +44,9 @@ class MultiRegionGridScan(ScanBase):
44
44
  "Acquisition Parameters": ["exp_time", "settling_time", "burst_at_each_point"],
45
45
  }
46
46
 
47
+ position_preview = "bec_lib.position_generators.multi_region_grid_positions"
48
+ position_preview_parameter_mapping = {"regions": "regions", "snaked": "snaked"}
49
+
47
50
  def __init__(
48
51
  self,
49
52
  motor1: DeviceBase,
@@ -18,9 +18,9 @@ from __future__ import annotations
18
18
 
19
19
  import numpy as np
20
20
 
21
+ from bec_lib import position_generators
21
22
  from bec_lib.device import DeviceBase
22
23
  from bec_lib.scan_args import DefaultArgType
23
- from bec_server.scan_server.scans import position_generators
24
24
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
25
25
  from bec_server.scan_server.scans.scan_modifier import scan_hook
26
26
 
@@ -50,6 +50,9 @@ class MultiRegionLineScan(ScanBase):
50
50
  ],
51
51
  }
52
52
 
53
+ position_preview = "bec_lib.position_generators.multi_region_line_positions"
54
+ position_preview_parameter_mapping = {"regions": "regions"}
55
+
53
56
  def __init__(
54
57
  self,
55
58
  motor: DeviceBase,
@@ -0,0 +1,5 @@
1
+ """Compatibility imports; use :mod:`bec_lib.path_optimization` for new code."""
2
+
3
+ from bec_lib.path_optimization import PathOptimizerMixin, PathQualityStats
4
+
5
+ __all__ = ["PathOptimizerMixin", "PathQualityStats"]
@@ -0,0 +1,33 @@
1
+ """Compatibility imports; use :mod:`bec_lib.position_generators` for new code."""
2
+
3
+ from bec_lib.position_generators import (
4
+ Direction,
5
+ fermat_spiral_pos,
6
+ get_round_roi_scan_positions,
7
+ hex_grid_2d,
8
+ line_scan_positions,
9
+ log_scan_positions,
10
+ multi_region_grid_positions,
11
+ multi_region_line_positions,
12
+ nd_grid_positions,
13
+ oscillating_positions,
14
+ rotate_points,
15
+ round_scan_positions,
16
+ spiral_positions,
17
+ )
18
+
19
+ __all__ = [
20
+ "Direction",
21
+ "rotate_points",
22
+ "spiral_positions",
23
+ "line_scan_positions",
24
+ "log_scan_positions",
25
+ "oscillating_positions",
26
+ "multi_region_line_positions",
27
+ "multi_region_grid_positions",
28
+ "nd_grid_positions",
29
+ "fermat_spiral_pos",
30
+ "round_scan_positions",
31
+ "get_round_roi_scan_positions",
32
+ "hex_grid_2d",
33
+ ]
@@ -20,9 +20,9 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.scan_args import DefaultArgType, ScanArgument
25
- from bec_server.scan_server.scans import position_generators
26
26
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
27
27
  from bec_server.scan_server.scans.scan_modifier import scan_hook
28
28
 
@@ -54,6 +54,18 @@ class RoundROIScan(ScanBase):
54
54
  ],
55
55
  }
56
56
 
57
+ position_preview = "bec_lib.position_generators.get_round_roi_scan_positions"
58
+ position_preview_parameter_mapping = {
59
+ "motor_1_start": "start_motor_1",
60
+ "motor_1_stop": "stop_motor_1",
61
+ "motor_2_start": "start_motor_2",
62
+ "motor_2_stop": "stop_motor_2",
63
+ "radial_step": "shell_spacing",
64
+ "points_in_first_shell": "pos_in_first_ring",
65
+ "center_1": "center_1",
66
+ "center_2": "center_2",
67
+ }
68
+
57
69
  def __init__(
58
70
  self,
59
71
  motor_1: DeviceBase,
@@ -20,9 +20,9 @@ from typing import Annotated
20
20
 
21
21
  import numpy as np
22
22
 
23
+ from bec_lib import position_generators
23
24
  from bec_lib.device import DeviceBase
24
25
  from bec_lib.scan_args import DefaultArgType, ScanArgument
25
- from bec_server.scan_server.scans import position_generators
26
26
  from bec_server.scan_server.scans.scan_base import ScanBase, ScanType
27
27
  from bec_server.scan_server.scans.scan_modifier import scan_hook
28
28
 
@@ -60,6 +60,16 @@ class RoundScan(ScanBase):
60
60
  ],
61
61
  }
62
62
 
63
+ position_preview = "bec_lib.position_generators.round_scan_positions"
64
+ position_preview_parameter_mapping = {
65
+ "inner_radius": "inner_radius",
66
+ "outer_radius": "outer_radius",
67
+ "number_of_rings": "number_of_rings",
68
+ "points_in_first_ring": "pos_in_first_ring",
69
+ "center_1": "center_1",
70
+ "center_2": "center_2",
71
+ }
72
+
63
73
  def __init__(
64
74
  self,
65
75
  motor_1: DeviceBase,
@@ -64,6 +64,10 @@ class ScanInfo(BaseModel):
64
64
  scan_number: Annotated[int | None, Field(description="Scan number, if applicable")] = None
65
65
  dataset_number: Annotated[int | None, Field(description="Dataset number, if applicable")] = None
66
66
 
67
+ # Preview metadata uses the same mapping as the advertised scan definition.
68
+ position_preview: str | None = None
69
+ position_preview_parameter_mapping: dict = Field(default_factory=dict)
70
+
67
71
  # Scan parameters
68
72
  num_points: Annotated[int, Field(description="Number of points in the scan.")] = 0
69
73
  positions: Annotated[
@@ -168,6 +172,8 @@ class ScanBase(ABC):
168
172
  arg_bundle_size = {"bundle": len(arg_input), "min": None, "max": None}
169
173
  is_scan = True
170
174
  is_internal = False
175
+ position_preview: str | None = None
176
+ position_preview_parameter_mapping: dict = {}
171
177
 
172
178
  def __init__(
173
179
  self,
@@ -207,7 +213,12 @@ class ScanBase(ABC):
207
213
  if data is not None:
208
214
  optional_kwargs[kwarg] = data
209
215
  self.scan_info = ScanInfo(
210
- scan_name=self.scan_name, scan_id=scan_id, scan_type=self.scan_type, **optional_kwargs
216
+ scan_name=self.scan_name,
217
+ scan_id=scan_id,
218
+ scan_type=self.scan_type,
219
+ position_preview=self.position_preview,
220
+ position_preview_parameter_mapping=self.position_preview_parameter_mapping,
221
+ **optional_kwargs,
211
222
  )
212
223
  self.update_scan_info(monitored=monitored, on_request=on_request)
213
224
 
@@ -6,9 +6,9 @@ from typing import TYPE_CHECKING, Callable, Literal
6
6
  import numpy as np
7
7
 
8
8
  from bec_lib.device import DeviceBase
9
+ from bec_lib.path_optimization import PathOptimizerMixin
10
+ from bec_lib.position_generators import Direction
9
11
  from bec_server.scan_server.errors import LimitError
10
- from bec_server.scan_server.scans.path_optimization import PathOptimizerMixin
11
- from bec_server.scan_server.scans.position_generators import Direction
12
12
 
13
13
  if TYPE_CHECKING:
14
14
  from bec_lib.devicemanager import DeviceContainer
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec-server"
7
- version = "4.2.0"
7
+ version = "4.3.0"
8
8
  description = "BEC server"
9
9
  requires-python = ">=3.11"
10
10
  classifiers = [
@@ -324,6 +324,66 @@ def test_device_server_status_callback(
324
324
  logger.remove(sink_id)
325
325
 
326
326
 
327
+ @pytest.mark.parametrize("nested_target", [False, True])
328
+ @pytest.mark.parametrize("success", [False, True])
329
+ @pytest.mark.parametrize("action", ["set", "rpc"])
330
+ def test_status_callback_uses_requested_target_for_delegated_status(
331
+ device_server_mock, nested_target, success, action
332
+ ):
333
+ """A child-owned status must complete and refresh the requested device."""
334
+
335
+ class DelegatingDevice(Device):
336
+ readback = Cpt(Signal, kind=Kind.hinted)
337
+ confirm_energy = Cpt(Signal, kind=Kind.config)
338
+
339
+ device = DelegatingDevice(name="cff")
340
+ device._kind = Kind.normal
341
+ target = device.readback if nested_target else device
342
+ target_name = "cff.readback" if nested_target else "cff"
343
+ instr = messages.DeviceInstructionMessage(
344
+ device=target_name,
345
+ action=action,
346
+ parameter={"value": 2.25} if action == "set" else {"func": "set"},
347
+ metadata={"device_instr_id": "diid", "RID": "request-id", "response": True},
348
+ )
349
+ status = DeviceStatus(device.confirm_energy)
350
+ device_server = device_server_mock
351
+ device_server._add_status_object_info(status, instr, target)
352
+ if nested_target:
353
+ status.sub_id = 42
354
+ if success:
355
+ status.set_finished()
356
+ else:
357
+ status.set_exception(RuntimeError("Energy confirmation failed"))
358
+
359
+ with (
360
+ mock.patch.object(device_server, "_read_device") as read_device,
361
+ mock.patch.object(device_server, "_update_read_configuration") as read_configuration,
362
+ mock.patch.object(device_server.connector, "xadd") as xadd,
363
+ mock.patch.object(target, "unsubscribe") as unsubscribe_target,
364
+ mock.patch.object(device.confirm_energy, "unsubscribe") as unsubscribe_confirmation,
365
+ ):
366
+ device_server.status_callback(status)
367
+
368
+ read_device.assert_called_once_with(instr, new_status=False)
369
+ read_configuration.assert_not_called()
370
+ if nested_target:
371
+ unsubscribe_target.assert_called_once_with(42)
372
+ else:
373
+ unsubscribe_target.assert_not_called()
374
+ unsubscribe_confirmation.assert_not_called()
375
+ xadd.assert_called_once()
376
+ response = xadd.call_args.args[1]["data"]
377
+ assert response.device == target_name
378
+ assert response.success is success
379
+ if success:
380
+ assert response.metadata["error_info"] is None
381
+ else:
382
+ assert response.metadata["error_info"].exception_type == "RuntimeError"
383
+ assert "Energy confirmation failed" in response.metadata["error_info"].error_message
384
+ assert status.device is device.confirm_energy
385
+
386
+
327
387
  @pytest.mark.parametrize("status_success", [True, False])
328
388
  def test_device_server_status_callback_response_includes_error_info(
329
389
  device_server_mock, ophyd_device_mock, status_success
@@ -0,0 +1,61 @@
1
+ """Preview metadata must reproduce the trajectory executed by each scan."""
2
+
3
+ import inspect
4
+ import json
5
+
6
+ import numpy as np
7
+ import pytest
8
+
9
+ from bec_lib import position_generators
10
+ from bec_lib.scan_preview import generate_scan_positions
11
+ from bec_server.scan_server.scans import position_generators as legacy_generators
12
+
13
+
14
+ @pytest.mark.parametrize(
15
+ "name,args,kwargs",
16
+ [
17
+ ("line_scan", ("samx", -1, 1, "samy", -2, 2), {"steps": 5}),
18
+ ("log_scan", ("samx", -1, 1, "samy", -2, 2), {"steps": 5}),
19
+ ("grid_scan", ("samx", -1, 1, 3, "samy", -2, 2, 4), {"snaked": False}),
20
+ ("hexagonal_scan", ("samx", -1, 1, 0.5, "samy", -2, 2, 0.5), {}),
21
+ ("fermat_scan", ("samx", -1, 1, "samy", -2, 2, 0.5), {"spiral_type": 1}),
22
+ ("round_scan", ("samx", "samy", 0, 2, 3, 4), {"center_1": 1}),
23
+ ("round_roi_scan", ("samx", -2, 2, "samy", -2, 2, 0.5, 4), {"center_2": 1}),
24
+ ("multi_region_line_scan", ("samx",), {"regions": [(-1, 0, 3), (0, 2, 4)]}),
25
+ ("multi_region_grid_scan", ("samx", "samy"), {"regions": [((-1, 1, 3), (-2, 2, 4))]}),
26
+ ],
27
+ )
28
+ def test_advertised_preview_matches_scan(scan_assembler, name, args, kwargs):
29
+ scan = scan_assembler(name, *args, relative=False, **kwargs)
30
+ cls = type(scan)
31
+ bound = inspect.signature(cls).bind(*args, relative=False, **kwargs)
32
+ bound.apply_defaults()
33
+ info = json.loads(
34
+ json.dumps(
35
+ {
36
+ "position_preview": cls.position_preview,
37
+ "position_preview_parameter_mapping": cls.position_preview_parameter_mapping,
38
+ "arg_bundle_size": cls.arg_bundle_size,
39
+ }
40
+ )
41
+ )
42
+ preview = generate_scan_positions(info, bound.arguments)
43
+ scan.prepare_scan()
44
+ np.testing.assert_allclose(preview, scan.positions)
45
+ assert scan.scan_info.position_preview == info["position_preview"]
46
+ assert (
47
+ scan.scan_info.position_preview_parameter_mapping
48
+ == info["position_preview_parameter_mapping"]
49
+ )
50
+
51
+ published_info = scan.actions._build_scan_status_info({}, {}, None)
52
+ assert published_info["position_preview"] == info["position_preview"]
53
+ assert (
54
+ published_info["position_preview_parameter_mapping"]
55
+ == info["position_preview_parameter_mapping"]
56
+ )
57
+
58
+
59
+ def test_legacy_import_preserves_function_and_direction_identity():
60
+ assert legacy_generators.line_scan_positions is position_generators.line_scan_positions
61
+ assert legacy_generators.Direction is position_generators.Direction
@@ -0,0 +1,14 @@
1
+ """Legacy optimizer imports must preserve the shared implementation identity."""
2
+
3
+ from bec_lib.path_optimization import PathOptimizerMixin, PathQualityStats
4
+ from bec_server.scan_server.scans.path_optimization import (
5
+ PathOptimizerMixin as LegacyPathOptimizerMixin,
6
+ )
7
+ from bec_server.scan_server.scans.path_optimization import (
8
+ PathQualityStats as LegacyPathQualityStats,
9
+ )
10
+
11
+
12
+ def test_legacy_optimizer_imports_preserve_identity():
13
+ assert LegacyPathOptimizerMixin is PathOptimizerMixin
14
+ assert LegacyPathQualityStats is PathQualityStats
@@ -222,3 +222,14 @@ def test_scan_manager_plugins_require_current_scan_base():
222
222
  def test_scan_manager_preserves_published_scan_base_class(scan_manager):
223
223
  assert scan_manager.available_scans
224
224
  assert {info["base_class"] for info in scan_manager.available_scans.values()} == {"ScanBaseV4"}
225
+
226
+
227
+ def test_scan_manager_advertises_preview_metadata(scan_manager):
228
+ info = scan_manager.available_scans["line_scan"]
229
+ assert info["position_preview"] == "bec_lib.position_generators.line_scan_positions"
230
+ assert info["position_preview_parameter_mapping"] == {
231
+ "axes": {"bundle": [1, 2]},
232
+ "steps": "steps",
233
+ }
234
+ assert scan_manager.available_scans["time_scan"]["position_preview"] is None
235
+ assert scan_manager.available_scans["time_scan"]["position_preview_parameter_mapping"] == {}