bec-server 4.1.2__tar.gz → 4.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. {bec_server-4.1.2 → bec_server-4.1.4}/PKG-INFO +1 -1
  2. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/async_writer.py +2 -1
  3. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/file_writer_manager.py +6 -4
  4. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_queue.py +29 -7
  5. {bec_server-4.1.2 → bec_server-4.1.4}/pyproject.toml +1 -1
  6. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_device_manager_ds.py +27 -0
  7. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_file_writer/test_file_writer_manager.py +95 -1
  8. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_server_queue.py +123 -0
  9. {bec_server-4.1.2 → bec_server-4.1.4}/.gitignore +0 -0
  10. {bec_server-4.1.2 → bec_server-4.1.4}/.zed/debug.json +0 -0
  11. {bec_server-4.1.2 → bec_server-4.1.4}/README.md +0 -0
  12. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/__init__.py +0 -0
  13. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/__init__.py +0 -0
  14. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/actor.py +0 -0
  15. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/builtin_actor_manager.py +0 -0
  16. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/manager.py +0 -0
  17. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/scan_interlock.py +0 -0
  18. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/actors/worker.py +0 -0
  19. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/bec_server_utils/__init__.py +0 -0
  20. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/bec_server_utils/launch.py +0 -0
  21. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/bec_server_utils/service_handler.py +0 -0
  22. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/bec_server_utils/subprocess_launch.py +0 -0
  23. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/bec_server_utils/tmux_launch.py +0 -0
  24. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/__init__.py +0 -0
  25. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/cli/__init__.py +0 -0
  26. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/cli/launch.py +0 -0
  27. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/dap_server.py +0 -0
  28. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/dap_service.py +0 -0
  29. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/dap_service_manager.py +0 -0
  30. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/data_processing/lmfit1d_service.py +0 -0
  31. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/__init__.py +0 -0
  32. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/bec_message_handler.py +0 -0
  33. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/cli/__init__.py +0 -0
  34. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/cli/launch.py +0 -0
  35. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/device_server.py +0 -0
  36. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/devices/__init__.py +0 -0
  37. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/devices/config_update_handler.py +0 -0
  38. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/devices/device_serializer.py +0 -0
  39. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/devices/devicemanager.py +0 -0
  40. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/friendly_device_exceptions.py +0 -0
  41. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/ophyd_callback_monitor.py +0 -0
  42. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/rpc_handler.py +0 -0
  43. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/tests/__init__.py +0 -0
  44. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/device_server/tests/utils.py +0 -0
  45. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/__init__.py +0 -0
  46. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/cli/__init__.py +0 -0
  47. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/cli/launch.py +0 -0
  48. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/default_writer.py +0 -0
  49. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/file_writer.py +0 -0
  50. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/file_writer/merged_dicts.py +0 -0
  51. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/Containerfile.bec_linux_base +0 -0
  52. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/Containerfile.requirements +0 -0
  53. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/Containerfile.worker +0 -0
  54. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/__init__.py +0 -0
  55. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/_dev_runner.py +0 -0
  56. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/builtin_procedures.py +0 -0
  57. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/constants.py +0 -0
  58. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/container_utils.py +0 -0
  59. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/container_worker.py +0 -0
  60. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/manager.py +0 -0
  61. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/oop_worker_base.py +0 -0
  62. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/procedure_registry.py +0 -0
  63. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/protocol.py +0 -0
  64. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/subprocess_worker.py +0 -0
  65. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/procedures/worker_base.py +0 -0
  66. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/__init__.py +0 -0
  67. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/bec_emitter.py +0 -0
  68. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/cli/__init__.py +0 -0
  69. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/cli/launch.py +0 -0
  70. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/emitter.py +0 -0
  71. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_bundler/scan_bundler.py +0 -0
  72. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/__init__.py +0 -0
  73. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/beamline_state_manager.py +0 -0
  74. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/cli/__init__.py +0 -0
  75. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/cli/launch.py +0 -0
  76. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/device_lock_registry.py +0 -0
  77. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/direct_scan_worker.py +0 -0
  78. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/errors.py +0 -0
  79. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/instruction_handler.py +0 -0
  80. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_assembler.py +0 -0
  81. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_guard.py +0 -0
  82. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_manager.py +0 -0
  83. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_server.py +0 -0
  84. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scan_worker.py +0 -0
  85. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/__init__.py +0 -0
  86. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/acquire.py +0 -0
  87. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/cont_line_scan.py +0 -0
  88. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/device_rpc.py +0 -0
  89. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/fermat_scan.py +0 -0
  90. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/grid_scan.py +0 -0
  91. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/hexagonal_scan.py +0 -0
  92. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/line_scan.py +0 -0
  93. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/line_sweep_scan.py +0 -0
  94. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/list_scan.py +0 -0
  95. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/log_scan.py +0 -0
  96. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/move.py +0 -0
  97. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/multi_region_grid_scan.py +0 -0
  98. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/multi_region_line_scan.py +0 -0
  99. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/path_optimization.py +0 -0
  100. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/position_generators.py +0 -0
  101. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/round_roi_scan.py +0 -0
  102. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/round_scan.py +0 -0
  103. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_actions.py +0 -0
  104. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_argument_modifier.py +0 -0
  105. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_base.py +0 -0
  106. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_components.py +0 -0
  107. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_modifier.py +0 -0
  108. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/scan_status.py +0 -0
  109. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/time_scan.py +0 -0
  110. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/scans/updated_move.py +0 -0
  111. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/tests/__init__.py +0 -0
  112. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/tests/fixtures.py +0 -0
  113. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/tests/scan_fixtures.py +0 -0
  114. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/tests/scan_hook_tests.py +0 -0
  115. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scan_server/tests/utils.py +0 -0
  116. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/__init__.py +0 -0
  117. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/__init__.py +0 -0
  118. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/atlas_active_client_emitter.py +0 -0
  119. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/atlas_connector.py +0 -0
  120. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/atlas_forwarder.py +0 -0
  121. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/atlas_metadata_handler.py +0 -0
  122. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/atlas_plugin_repo_emitter.py +0 -0
  123. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/atlas/config_handler.py +0 -0
  124. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/cli/__init__.py +0 -0
  125. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/cli/launch.py +0 -0
  126. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/scihub.py +0 -0
  127. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/service_handler/__init__.py +0 -0
  128. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/scihub/service_handler/service_handler.py +0 -0
  129. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/test/__init__.py +0 -0
  130. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/test/actor_test_utils.py +0 -0
  131. {bec_server-4.1.2 → bec_server-4.1.4}/bec_server/test/helpers.py +0 -0
  132. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_actors/test_actors.py +0 -0
  133. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_bec_server_utils/test_main.py +0 -0
  134. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_bec_server_utils/test_service_handler.py +0 -0
  135. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_bec_server_utils/test_subprocess_launch.py +0 -0
  136. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_bec_server_utils/test_tmux_launch.py +0 -0
  137. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_data_processing/conftest.py +0 -0
  138. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_data_processing/test_dap_cli_launch.py +0 -0
  139. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_data_processing/test_dap_server.py +0 -0
  140. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_data_processing/test_dap_service_manager.py +0 -0
  141. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_data_processing/test_lmfit1d_service.py +0 -0
  142. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/conftest.py +0 -0
  143. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_config_handler.py +0 -0
  144. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_device_instructions.py +0 -0
  145. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_device_serializer.py +0 -0
  146. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_device_server.py +0 -0
  147. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_device_server_cli_launch.py +0 -0
  148. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_ophyd_callback_monitor.py +0 -0
  149. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_device_server/test_rpc_handler.py +0 -0
  150. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_file_writer/conftest.py +0 -0
  151. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_file_writer/test_async_file_writer.py +0 -0
  152. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_file_writer/test_file_writer.py +0 -0
  153. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_file_writer/test_file_writer_cli_launch.py +0 -0
  154. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_bundler/conftest.py +0 -0
  155. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_bundler/test_bec_emitter.py +0 -0
  156. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_bundler/test_scan_bundler.py +0 -0
  157. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_bundler/test_scan_bundler_cli_launch.py +0 -0
  158. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/conftest.py +0 -0
  159. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/__init__.py +0 -0
  160. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_acquire.py +0 -0
  161. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_cont_line_scan.py +0 -0
  162. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_device_rpc_scan.py +0 -0
  163. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_fermat_scan.py +0 -0
  164. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_grid_scan.py +0 -0
  165. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_hexagonal_scan.py +0 -0
  166. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_line_scan.py +0 -0
  167. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_line_sweep_scan.py +0 -0
  168. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_list_scan.py +0 -0
  169. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_log_scan.py +0 -0
  170. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_move_scan.py +0 -0
  171. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_multi_region_grid_scan.py +0 -0
  172. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_multi_region_line_scan.py +0 -0
  173. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_position_generators.py +0 -0
  174. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_relative_scan_return_to_start.py +0 -0
  175. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_round_roi_scan.py +0 -0
  176. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_round_scan.py +0 -0
  177. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_scan_actions.py +0 -0
  178. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_scan_components.py +0 -0
  179. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_scan_status.py +0 -0
  180. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_time_scan.py +0 -0
  181. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/scans/test_updated_move_scan.py +0 -0
  182. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_beamline_state_manager.py +0 -0
  183. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_builtin_actor_manager.py +0 -0
  184. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_container_utils.py +0 -0
  185. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_device_lock_registry.py +0 -0
  186. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_direct_scan_worker.py +0 -0
  187. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_instruction_handler.py +0 -0
  188. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_path_optimization.py +0 -0
  189. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_procedure_container_worker.py +0 -0
  190. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_procedures.py +0 -0
  191. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_argument_modifier.py +0 -0
  192. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_assembler.py +0 -0
  193. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_fixture_imports.py +0 -0
  194. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_guard.py +0 -0
  195. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_interlock.py +0 -0
  196. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_modifier.py +0 -0
  197. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_server_cli_launch.py +0 -0
  198. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_server_scan_manager.py +0 -0
  199. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scan_server/test_scan_worker.py +0 -0
  200. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/conftest.py +0 -0
  201. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_active_client_emitter.py +0 -0
  202. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_config_handler.py +0 -0
  203. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_connector.py +0 -0
  204. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_forwarder.py +0 -0
  205. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_metadata_handler.py +0 -0
  206. {bec_server-4.1.2 → bec_server-4.1.4}/tests/tests_scihub/test_atlas_plugin_repo_emitter.py +0 -0
  207. {bec_server-4.1.2 → bec_server-4.1.4}/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.1.2
3
+ Version: 4.1.4
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
@@ -111,6 +111,7 @@ class AsyncWriter(threading.Thread):
111
111
  self._written_signals = defaultdict(set)
112
112
  self.file_handle = None
113
113
  self.cursor = defaultdict(dict)
114
+ self.error_info: messages.ErrorInfo | None = None
114
115
 
115
116
  @property
116
117
  def written_signals(self) -> dict[str, list[str]]:
@@ -215,13 +216,13 @@ class AsyncWriter(threading.Thread):
215
216
  # pylint: disable=broad-except
216
217
  except Exception:
217
218
  content = traceback.format_exc()
218
- # self.send_file_message(done=True, successful=False)
219
219
  logger.error(f"Error writing async data file {self.tmp_file_path}: {content}")
220
220
  error_info = messages.ErrorInfo(
221
221
  error_message=f"Error writing async data file {self.tmp_file_path}",
222
222
  compact_error_message=traceback.format_exc(limit=0),
223
223
  exception_type="AsyncWriterError",
224
224
  )
225
+ self.error_info = error_info
225
226
  self.connector.raise_alarm(
226
227
  severity=Alarms.WARNING,
227
228
  info=error_info,
@@ -422,6 +422,8 @@ class FileWriterManager(BECService):
422
422
  file_suffix = "master"
423
423
 
424
424
  start_time = time.time()
425
+ successful = storage.async_writer is None or storage.async_writer.error_info is None
426
+ file_handle = None
425
427
 
426
428
  try:
427
429
  file_path = get_full_path(
@@ -429,7 +431,6 @@ class FileWriterManager(BECService):
429
431
  name=file_suffix,
430
432
  log_if_dir_does_not_exist=False,
431
433
  )
432
- successful = True
433
434
  written_async_signals = (
434
435
  storage.async_writer.written_signals if storage.async_writer else None
435
436
  )
@@ -491,6 +492,9 @@ class FileWriterManager(BECService):
491
492
  expire=3600,
492
493
  )
493
494
 
495
+ if not successful:
496
+ return
497
+
494
498
  history_msg = messages.ScanHistoryMessage(
495
499
  scan_id=scan_id,
496
500
  scan_number=storage.scan_number,
@@ -509,6 +513,4 @@ class FileWriterManager(BECService):
509
513
  self.connector.xadd(
510
514
  topic=MessageEndpoints.scan_history(), msg_dict={"data": history_msg}, max_size=10000
511
515
  )
512
- if successful:
513
- logger.success(f"Finished writing file {file_path}.")
514
- return
516
+ logger.success(f"Finished writing file {file_path}.")
@@ -459,15 +459,19 @@ class QueueManager:
459
459
  Expected: {instruction_queue}, actual: {instruction_queue.worker.current_instruction_queue_item}. Skipping abort."
460
460
  )
461
461
  return
462
- que.worker_status = InstructionQueueStatus.STOPPED
463
462
  if instruction_queue.scan_id and instruction_queue.scan_id[-1] is None:
464
463
  stop_id = instruction_queue.queue_id
465
464
  else:
466
465
  stop_id = instruction_queue.scan_id
467
- self.stop_all_devices(
468
- stop_id=stop_id,
469
- devices=self._get_owned_devices_for_instruction_queue(instruction_queue),
470
- )
466
+ try:
467
+ self.stop_all_devices(
468
+ stop_id=stop_id,
469
+ devices=self._get_owned_devices_for_instruction_queue(instruction_queue),
470
+ )
471
+ finally:
472
+ # Attempt publication before cleanup, but still interrupt on publish failure.
473
+ if instruction_queue.status != InstructionQueueStatus.COMPLETED:
474
+ instruction_queue.status = InstructionQueueStatus.STOPPED
471
475
 
472
476
  def _cancel_queue_item(self, target_queue_item: DirectInstructionQueueItem, queue: str) -> None:
473
477
  """
@@ -528,8 +532,26 @@ class QueueManager:
528
532
  que = self.queues[queue]
529
533
  with AutoResetCM(que):
530
534
  que.status = ScanQueueStatus.PAUSED
531
- que.worker_status = InstructionQueueStatus.STOPPED
532
- que.clear()
535
+ instruction_queue = que.scan_worker.current_instruction_queue_item
536
+ if (
537
+ instruction_queue is not None
538
+ and instruction_queue.status != InstructionQueueStatus.COMPLETED
539
+ ):
540
+ scan_ids = instruction_queue.scan_id
541
+ stop_id = (
542
+ instruction_queue.queue_id if scan_ids and scan_ids[-1] is None else scan_ids
543
+ )
544
+ try:
545
+ self.stop_all_devices(
546
+ stop_id=stop_id,
547
+ devices=self._get_owned_devices_for_instruction_queue(instruction_queue),
548
+ )
549
+ finally:
550
+ instruction_queue.status = InstructionQueueStatus.STOPPED
551
+ que.clear()
552
+ else:
553
+ que.worker_status = InstructionQueueStatus.STOPPED
554
+ que.clear()
533
555
 
534
556
  @requires_queue
535
557
  def set_restart(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec-server"
7
- version = "4.1.2"
7
+ version = "4.1.4"
8
8
  description = "BEC server"
9
9
  requires-python = ">=3.11"
10
10
  classifiers = [
@@ -12,6 +12,7 @@ from ophyd_devices.tests.utils import patched_device
12
12
 
13
13
  from bec_lib import messages
14
14
  from bec_lib.bec_errors import DeviceConfigError
15
+ from bec_lib.connector import MessageObject
15
16
  from bec_lib.endpoints import MessageEndpoints
16
17
  from bec_server.device_server.devices.config_update_handler import ConfigUpdateHandler
17
18
  from bec_server.device_server.devices.devicemanager import DeviceManagerDS
@@ -20,6 +21,32 @@ from bec_server.device_server.devices.devicemanager import DeviceManagerDS
20
21
  # pylint: disable=protected-access
21
22
 
22
23
 
24
+ @pytest.mark.parametrize("device_manager_class", [DeviceManagerDS])
25
+ @pytest.mark.parametrize("metadata", [{}, {"RID": "reload-request"}])
26
+ def test_reload_notification_does_not_change_device_server_status(device_manager, metadata):
27
+ device_manager._service._service_name = "DeviceServer"
28
+ msg = messages.DeviceConfigMessage(action="reload", config={}, metadata=metadata)
29
+ with (
30
+ mock.patch.object(device_manager, "update_status") as update_status,
31
+ mock.patch.object(device_manager, "_reload_action") as reload_action,
32
+ mock.patch.object(device_manager.connector, "lpush") as lpush,
33
+ ):
34
+ device_manager._device_config_update_callback(MessageObject(value=msg, topic=""))
35
+
36
+ update_status.assert_not_called()
37
+ reload_action.assert_not_called()
38
+ if metadata:
39
+ lpush.assert_called_once_with(
40
+ MessageEndpoints.service_response(metadata["RID"]),
41
+ messages.ServiceResponseMessage(
42
+ response={"accepted": True, "service": device_manager._service._service_name}
43
+ ),
44
+ expire=100,
45
+ )
46
+ else:
47
+ lpush.assert_not_called()
48
+
49
+
23
50
  @pytest.fixture
24
51
  def dm_with_devices_and_status(dm_with_devices):
25
52
  """
@@ -2,6 +2,7 @@
2
2
  import os
3
3
  import threading
4
4
  import time
5
+ from pathlib import Path
5
6
  from unittest import mock
6
7
 
7
8
  import numpy as np
@@ -15,6 +16,7 @@ from bec_lib.redis_connector import MessageObject
15
16
  from bec_lib.service_config import ServiceConfig
16
17
  from bec_lib.tests.utils import ConnectorMock
17
18
  from bec_server.file_writer import FileWriterManager
19
+ from bec_server.file_writer.async_writer import AsyncWriter
18
20
  from bec_server.file_writer.file_writer import HDF5FileWriter
19
21
  from bec_server.file_writer.file_writer_manager import ScanStorage
20
22
 
@@ -242,7 +244,7 @@ def test_write_file(file_writer_manager_mock, scan_storage_mock):
242
244
  def test_write_file_forwards_written_async_signals(file_writer_manager_mock, scan_storage_mock):
243
245
  file_manager = file_writer_manager_mock
244
246
  scan_storage_mock.async_writer = mock.Mock(
245
- written_signals={"waveform": ["waveform_data"]}, file_handle=None
247
+ written_signals={"waveform": ["waveform_data"]}, file_handle=None, error_info=None
246
248
  )
247
249
  file_manager.scan_storage["scan_id"] = scan_storage_mock
248
250
 
@@ -839,3 +841,95 @@ def test_subscriptions_buffer_early_notifications(file_writer_manager_mock, conn
839
841
  assert manager.scan_storage["scan_id"].file_references == {"eiger": file_msg}
840
842
  assert manager._pending_baseline_writes == {}
841
843
  assert manager._pending_file_references == {}
844
+
845
+
846
+ @pytest.mark.parametrize("failure_stage", ["poll", "write", "final_poll", None])
847
+ @pytest.mark.parametrize("finalization_fails", [False, True])
848
+ def test_async_failure_survives_finalization(
849
+ file_writer_manager_mock,
850
+ scan_storage_mock,
851
+ tmp_path,
852
+ failure_stage,
853
+ finalization_fails,
854
+ request,
855
+ ):
856
+ manager = file_writer_manager_mock
857
+ path = str(tmp_path / "master.h5")
858
+ writer = AsyncWriter(path, "scan_id", 10, manager.connector, ["det"], [])
859
+
860
+ def close_file():
861
+ if writer.file_handle is not None:
862
+ writer.file_handle.close()
863
+
864
+ request.addfinalizer(close_file)
865
+ scan_storage_mock.async_writer = writer
866
+ manager.scan_storage["scan_id"] = scan_storage_mock
867
+ data = {
868
+ "det": [
869
+ messages.DeviceMessage(
870
+ signals={"det": {"value": [1], "timestamp": 1}},
871
+ metadata={"async_update": {"type": "add", "max_shape": [None]}},
872
+ )
873
+ ]
874
+ }
875
+ failure = RuntimeError("async acquisition failed")
876
+
877
+ def poll(poll_timeout=500):
878
+ if writer.written_signals:
879
+ if failure_stage in ("poll", "final_poll"):
880
+ raise failure
881
+ writer.stop()
882
+ return None
883
+ return data
884
+
885
+ original_write = writer.write_data
886
+
887
+ def write(*args, **kwargs):
888
+ original_write(*args, **kwargs)
889
+ if failure_stage == "write":
890
+ raise failure
891
+ if failure_stage == "final_poll":
892
+ writer.stop()
893
+
894
+ with (
895
+ mock.patch.object(writer, "poll_data", side_effect=poll),
896
+ mock.patch.object(writer, "write_data", side_effect=write),
897
+ mock.patch.object(manager.connector, "raise_alarm"),
898
+ ):
899
+ # Error propagation does not require a background thread or a timing deadline.
900
+ writer.run()
901
+ assert writer.written_signals == {"det": ["det"]}
902
+ assert writer.file_handle["/entry/collection/devices/det/det/value"][:].tolist() == [1]
903
+ if failure_stage:
904
+ assert "async acquisition failed" in writer.error_info.compact_error_message
905
+ else:
906
+ assert writer.error_info is None
907
+ with (
908
+ mock.patch("bec_server.file_writer.file_writer_manager.get_full_path", return_value=path),
909
+ mock.patch.object(
910
+ manager.file_writer,
911
+ "write",
912
+ side_effect=RuntimeError("metadata failed") if finalization_fails else None,
913
+ ) as finalize,
914
+ mock.patch.object(manager.connector, "set_and_publish") as publish,
915
+ mock.patch.object(manager.connector, "xadd") as xadd,
916
+ mock.patch.object(manager.connector, "raise_alarm"),
917
+ ):
918
+ manager.write_file("scan_id")
919
+ finalize.assert_called_once()
920
+ outcome = publish.call_args.args[1]
921
+ assert outcome.done is True
922
+ assert outcome.successful is (failure_stage is None and not finalization_fails)
923
+ # The logger may also publish through this connector, depending on test order.
924
+ history_calls = [
925
+ call
926
+ for call in xadd.call_args_list
927
+ if call.kwargs.get("topic") == MessageEndpoints.scan_history()
928
+ ]
929
+ if outcome.successful:
930
+ assert len(history_calls) == 1
931
+ assert history_calls[0].kwargs["msg_dict"]["data"].file_path == path
932
+ else:
933
+ assert not history_calls
934
+ assert not writer.file_handle.id.valid
935
+ assert Path(path).exists()
@@ -1,5 +1,6 @@
1
1
  import threading
2
2
  import time
3
+ from contextlib import nullcontext
3
4
  from unittest import mock
4
5
 
5
6
  import pytest
@@ -1017,6 +1018,128 @@ def test_set_abort_with_no_owned_devices_sends_stop_none(queuemanager_mock):
1017
1018
  } in queue_manager.connector.message_sent
1018
1019
 
1019
1020
 
1021
+ @pytest.mark.parametrize("action", ["abort", "clear"])
1022
+ @pytest.mark.parametrize("has_scan_id", [False, True])
1023
+ @pytest.mark.parametrize("publish_fails", [False, True])
1024
+ def test_device_stop_precedes_worker_shutdown(
1025
+ dormant_scan_queue, action, has_scan_id, publish_fails
1026
+ ):
1027
+ queue = dormant_scan_queue
1028
+ manager = queue.queue_manager
1029
+ registry = manager.parent.device_lock_registry
1030
+ item = DirectInstructionQueueItem(queue, mock.Mock(), queue.scan_worker)
1031
+ scan = _build_dummy_v4_scan("scan-id" if has_scan_id else None)
1032
+ scan.scan_info.metadata["RID"] = "stop-rid"
1033
+ item.scans = [scan]
1034
+ item.scan_msgs = [_queued_scan_message(rid="stop-rid")]
1035
+ item.active_scan = scan
1036
+ queue.queue.append(item)
1037
+ queue.active_instruction_queue = item
1038
+ queue.scan_worker.current_instruction_queue_item = item
1039
+ item.status = InstructionQueueStatus.RUNNING
1040
+ registry.get_owned_devices = mock.Mock(return_value=["samx"])
1041
+ manager.connector.message_sent = []
1042
+ original_stop = item.stop
1043
+
1044
+ def release_on_shutdown():
1045
+ # Model the direct worker releasing ownership immediately on interruption.
1046
+ registry.get_owned_devices.return_value = []
1047
+ stops = [
1048
+ sent["msg"]
1049
+ for sent in manager.connector.message_sent
1050
+ if sent["queue"] == MessageEndpoints.stop_devices()
1051
+ ]
1052
+ if publish_fails:
1053
+ assert not stops
1054
+ else:
1055
+ assert len(stops) == 1
1056
+ assert stops[0].value == ["samx"]
1057
+ expected_stop_id = item.scan_id if has_scan_id else item.queue_id
1058
+ assert stops[0].metadata["stop_id"] == expected_stop_id
1059
+ original_stop()
1060
+
1061
+ def fail_stop_publication(endpoint, msg):
1062
+ assert endpoint == MessageEndpoints.stop_devices()
1063
+ assert msg.value == ["samx"]
1064
+ raise RuntimeError("Stop publication failed")
1065
+
1066
+ publication = (
1067
+ mock.patch.object(manager.connector, "send", side_effect=fail_stop_publication)
1068
+ if publish_fails
1069
+ else nullcontext()
1070
+ )
1071
+ expected_error = (
1072
+ pytest.raises(RuntimeError, match="Stop publication failed")
1073
+ if publish_fails
1074
+ else nullcontext()
1075
+ )
1076
+ with publication, mock.patch.object(item, "stop", side_effect=release_on_shutdown):
1077
+ with expected_error:
1078
+ getattr(manager, f"set_{action}")(queue="primary")
1079
+ assert item.status == InstructionQueueStatus.STOPPED
1080
+ assert queue.status == ScanQueueStatus.PAUSED
1081
+ if action == "clear":
1082
+ assert not queue.queue
1083
+ assert queue.active_instruction_queue is None
1084
+
1085
+
1086
+ @pytest.mark.parametrize("retire_target", [False, True])
1087
+ @pytest.mark.parametrize("publish_fails", [False, True])
1088
+ def test_abort_preserves_completed_target_and_following_item(
1089
+ dormant_scan_queue, retire_target, publish_fails
1090
+ ):
1091
+ # pylint: disable=redefined-outer-name
1092
+ queue = dormant_scan_queue
1093
+ manager = queue.queue_manager
1094
+ manager.add_to_queue("primary", _queued_scan_message(rid="original"))
1095
+ manager.add_to_queue("primary", _queued_scan_message(rid="following"))
1096
+ original, following = queue.queue
1097
+ original.active_scan = original.scans[0]
1098
+ original.status = InstructionQueueStatus.RUNNING
1099
+ queue.active_instruction_queue = original
1100
+ queue.scan_worker.current_instruction_queue_item = original
1101
+ send = manager.connector.send
1102
+
1103
+ def complete_during_publication(endpoint, msg):
1104
+ assert endpoint == MessageEndpoints.stop_devices()
1105
+ # Model the worker completing and optionally retiring the original during publication.
1106
+ original.status = InstructionQueueStatus.COMPLETED
1107
+ queue.scan_worker.current_instruction_queue_item = None
1108
+ if retire_target:
1109
+ assert queue.queue.popleft() is original
1110
+ if publish_fails:
1111
+ raise RuntimeError("Stop publication failed")
1112
+ send(endpoint, msg)
1113
+
1114
+ expected_error = (
1115
+ pytest.raises(RuntimeError, match="Stop publication failed")
1116
+ if publish_fails
1117
+ else nullcontext()
1118
+ )
1119
+ with mock.patch.object(manager.connector, "send", side_effect=complete_during_publication):
1120
+ with expected_error:
1121
+ manager.set_abort(request_id="original")
1122
+
1123
+ assert original.status == InstructionQueueStatus.COMPLETED
1124
+ assert following.status == InstructionQueueStatus.PENDING
1125
+ assert not following.scans[0]._shutdown_event.is_set()
1126
+ assert queue.status == ScanQueueStatus.PAUSED
1127
+
1128
+
1129
+ def test_clear_pending_queue_does_not_stop_devices(dormant_scan_queue):
1130
+ queue = dormant_scan_queue
1131
+ manager = queue.queue_manager
1132
+ manager.add_to_queue("primary", _queued_scan_message())
1133
+ manager.connector.message_sent = []
1134
+
1135
+ manager.set_clear(queue="primary")
1136
+
1137
+ assert not queue.queue
1138
+ assert not any(
1139
+ sent["queue"] == MessageEndpoints.stop_devices() for sent in manager.connector.message_sent
1140
+ )
1141
+
1142
+
1020
1143
  @pytest.mark.timeout(5)
1021
1144
  def test_set_clear_sends_message(queuemanager_mock):
1022
1145
  queue_manager = queuemanager_mock()
File without changes
File without changes
File without changes