bec-server 4.0.0__tar.gz → 4.0.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 (207) hide show
  1. {bec_server-4.0.0 → bec_server-4.0.2}/PKG-INFO +1 -1
  2. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/async_writer.py +83 -29
  3. {bec_server-4.0.0 → bec_server-4.0.2}/pyproject.toml +1 -1
  4. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_file_writer/test_async_file_writer.py +234 -0
  5. {bec_server-4.0.0 → bec_server-4.0.2}/.gitignore +0 -0
  6. {bec_server-4.0.0 → bec_server-4.0.2}/.zed/debug.json +0 -0
  7. {bec_server-4.0.0 → bec_server-4.0.2}/README.md +0 -0
  8. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/__init__.py +0 -0
  9. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/__init__.py +0 -0
  10. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/actor.py +0 -0
  11. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/builtin_actor_manager.py +0 -0
  12. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/manager.py +0 -0
  13. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/scan_interlock.py +0 -0
  14. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/actors/worker.py +0 -0
  15. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/bec_server_utils/__init__.py +0 -0
  16. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/bec_server_utils/launch.py +0 -0
  17. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/bec_server_utils/service_handler.py +0 -0
  18. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/bec_server_utils/subprocess_launch.py +0 -0
  19. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/bec_server_utils/tmux_launch.py +0 -0
  20. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/__init__.py +0 -0
  21. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/cli/__init__.py +0 -0
  22. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/cli/launch.py +0 -0
  23. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/dap_server.py +0 -0
  24. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/dap_service.py +0 -0
  25. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/dap_service_manager.py +0 -0
  26. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/data_processing/lmfit1d_service.py +0 -0
  27. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/__init__.py +0 -0
  28. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/bec_message_handler.py +0 -0
  29. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/cli/__init__.py +0 -0
  30. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/cli/launch.py +0 -0
  31. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/device_server.py +0 -0
  32. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/devices/__init__.py +0 -0
  33. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/devices/config_update_handler.py +0 -0
  34. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/devices/device_serializer.py +0 -0
  35. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/devices/devicemanager.py +0 -0
  36. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/friendly_device_exceptions.py +0 -0
  37. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/ophyd_callback_monitor.py +0 -0
  38. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/rpc_handler.py +0 -0
  39. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/tests/__init__.py +0 -0
  40. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/device_server/tests/utils.py +0 -0
  41. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/__init__.py +0 -0
  42. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/cli/__init__.py +0 -0
  43. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/cli/launch.py +0 -0
  44. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/default_writer.py +0 -0
  45. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/file_writer.py +0 -0
  46. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/file_writer_manager.py +0 -0
  47. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/file_writer/merged_dicts.py +0 -0
  48. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/Containerfile.bec_linux_base +0 -0
  49. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/Containerfile.requirements +0 -0
  50. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/Containerfile.worker +0 -0
  51. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/__init__.py +0 -0
  52. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/_dev_runner.py +0 -0
  53. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/builtin_procedures.py +0 -0
  54. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/constants.py +0 -0
  55. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/container_utils.py +0 -0
  56. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/container_worker.py +0 -0
  57. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/manager.py +0 -0
  58. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/oop_worker_base.py +0 -0
  59. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/procedure_registry.py +0 -0
  60. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/protocol.py +0 -0
  61. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/subprocess_worker.py +0 -0
  62. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/procedures/worker_base.py +0 -0
  63. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/__init__.py +0 -0
  64. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/bec_emitter.py +0 -0
  65. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/cli/__init__.py +0 -0
  66. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/cli/launch.py +0 -0
  67. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/emitter.py +0 -0
  68. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_bundler/scan_bundler.py +0 -0
  69. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/__init__.py +0 -0
  70. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/beamline_state_manager.py +0 -0
  71. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/cli/__init__.py +0 -0
  72. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/cli/launch.py +0 -0
  73. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/device_lock_registry.py +0 -0
  74. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/direct_scan_worker.py +0 -0
  75. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/errors.py +0 -0
  76. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/instruction_handler.py +0 -0
  77. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_assembler.py +0 -0
  78. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_guard.py +0 -0
  79. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_manager.py +0 -0
  80. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_queue.py +0 -0
  81. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_server.py +0 -0
  82. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scan_worker.py +0 -0
  83. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/__init__.py +0 -0
  84. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/acquire.py +0 -0
  85. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/cont_line_scan.py +0 -0
  86. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/device_rpc.py +0 -0
  87. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/fermat_scan.py +0 -0
  88. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/grid_scan.py +0 -0
  89. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/hexagonal_scan.py +0 -0
  90. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/line_scan.py +0 -0
  91. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/line_sweep_scan.py +0 -0
  92. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/list_scan.py +0 -0
  93. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/log_scan.py +0 -0
  94. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/move.py +0 -0
  95. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/multi_region_grid_scan.py +0 -0
  96. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/multi_region_line_scan.py +0 -0
  97. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/path_optimization.py +0 -0
  98. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/position_generators.py +0 -0
  99. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/round_roi_scan.py +0 -0
  100. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/round_scan.py +0 -0
  101. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_actions.py +0 -0
  102. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_argument_modifier.py +0 -0
  103. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_base.py +0 -0
  104. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_components.py +0 -0
  105. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_modifier.py +0 -0
  106. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/scan_status.py +0 -0
  107. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/time_scan.py +0 -0
  108. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/scans/updated_move.py +0 -0
  109. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/tests/__init__.py +0 -0
  110. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/tests/fixtures.py +0 -0
  111. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/tests/scan_fixtures.py +0 -0
  112. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/tests/scan_hook_tests.py +0 -0
  113. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scan_server/tests/utils.py +0 -0
  114. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/__init__.py +0 -0
  115. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/__init__.py +0 -0
  116. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/atlas_active_client_emitter.py +0 -0
  117. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/atlas_connector.py +0 -0
  118. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/atlas_forwarder.py +0 -0
  119. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/atlas_metadata_handler.py +0 -0
  120. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/atlas_plugin_repo_emitter.py +0 -0
  121. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/atlas/config_handler.py +0 -0
  122. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/cli/__init__.py +0 -0
  123. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/cli/launch.py +0 -0
  124. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/scihub.py +0 -0
  125. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/service_handler/__init__.py +0 -0
  126. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/scihub/service_handler/service_handler.py +0 -0
  127. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/test/__init__.py +0 -0
  128. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/test/actor_test_utils.py +0 -0
  129. {bec_server-4.0.0 → bec_server-4.0.2}/bec_server/test/helpers.py +0 -0
  130. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_actors/test_actors.py +0 -0
  131. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_bec_server_utils/test_main.py +0 -0
  132. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_bec_server_utils/test_service_handler.py +0 -0
  133. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_bec_server_utils/test_subprocess_launch.py +0 -0
  134. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_bec_server_utils/test_tmux_launch.py +0 -0
  135. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_data_processing/conftest.py +0 -0
  136. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_data_processing/test_dap_cli_launch.py +0 -0
  137. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_data_processing/test_dap_server.py +0 -0
  138. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_data_processing/test_dap_service_manager.py +0 -0
  139. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_data_processing/test_lmfit1d_service.py +0 -0
  140. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/conftest.py +0 -0
  141. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_config_handler.py +0 -0
  142. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_device_instructions.py +0 -0
  143. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_device_manager_ds.py +0 -0
  144. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_device_serializer.py +0 -0
  145. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_device_server.py +0 -0
  146. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_device_server_cli_launch.py +0 -0
  147. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_ophyd_callback_monitor.py +0 -0
  148. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_device_server/test_rpc_handler.py +0 -0
  149. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_file_writer/conftest.py +0 -0
  150. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_file_writer/test_file_writer.py +0 -0
  151. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_file_writer/test_file_writer_cli_launch.py +0 -0
  152. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_file_writer/test_file_writer_manager.py +0 -0
  153. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_bundler/conftest.py +0 -0
  154. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_bundler/test_bec_emitter.py +0 -0
  155. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_bundler/test_scan_bundler.py +0 -0
  156. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_bundler/test_scan_bundler_cli_launch.py +0 -0
  157. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/conftest.py +0 -0
  158. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/__init__.py +0 -0
  159. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_acquire.py +0 -0
  160. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_cont_line_scan.py +0 -0
  161. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_device_rpc_scan.py +0 -0
  162. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_fermat_scan.py +0 -0
  163. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_grid_scan.py +0 -0
  164. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_hexagonal_scan.py +0 -0
  165. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_line_scan.py +0 -0
  166. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_line_sweep_scan.py +0 -0
  167. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_list_scan.py +0 -0
  168. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_log_scan.py +0 -0
  169. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_move_scan.py +0 -0
  170. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_multi_region_grid_scan.py +0 -0
  171. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_multi_region_line_scan.py +0 -0
  172. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_position_generators.py +0 -0
  173. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_relative_scan_return_to_start.py +0 -0
  174. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_round_roi_scan.py +0 -0
  175. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_round_scan.py +0 -0
  176. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_scan_actions.py +0 -0
  177. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_scan_components.py +0 -0
  178. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_scan_status.py +0 -0
  179. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_time_scan.py +0 -0
  180. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/scans/test_updated_move_scan.py +0 -0
  181. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_beamline_state_manager.py +0 -0
  182. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_builtin_actor_manager.py +0 -0
  183. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_container_utils.py +0 -0
  184. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_device_lock_registry.py +0 -0
  185. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_direct_scan_worker.py +0 -0
  186. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_instruction_handler.py +0 -0
  187. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_path_optimization.py +0 -0
  188. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_procedure_container_worker.py +0 -0
  189. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_procedures.py +0 -0
  190. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_argument_modifier.py +0 -0
  191. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_assembler.py +0 -0
  192. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_fixture_imports.py +0 -0
  193. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_guard.py +0 -0
  194. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_interlock.py +0 -0
  195. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_modifier.py +0 -0
  196. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_server_cli_launch.py +0 -0
  197. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_server_queue.py +0 -0
  198. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_server_scan_manager.py +0 -0
  199. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scan_server/test_scan_worker.py +0 -0
  200. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/conftest.py +0 -0
  201. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_active_client_emitter.py +0 -0
  202. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_config_handler.py +0 -0
  203. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_connector.py +0 -0
  204. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_forwarder.py +0 -0
  205. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_metadata_handler.py +0 -0
  206. {bec_server-4.0.0 → bec_server-4.0.2}/tests/tests_scihub/test_atlas_plugin_repo_emitter.py +0 -0
  207. {bec_server-4.0.0 → bec_server-4.0.2}/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.0.0
3
+ Version: 4.0.2
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
@@ -65,7 +65,9 @@ class AsyncWriter(threading.Thread):
65
65
  "index": int
66
66
  }
67
67
 
68
- "index" is only required for the 'add_slice' type and specifies the row index to append the data to.
68
+ "index" is required for 'add_slice' and must be nonnegative. It selects the row whose
69
+ contents are extended and allows revisiting earlier rows. Use 'add' to append new rows
70
+ along the first axis; 'add' ignores "index".
69
71
  "max_shape" is required for the 'add' and 'add_slice' types and specifies the maximum shape of the dataset. If the dataset is 1D, 'max_shape' should be [None].
70
72
 
71
73
  """
@@ -301,7 +303,12 @@ class AsyncWriter(threading.Thread):
301
303
  if key == "value":
302
304
  self.write_value_data(signal_group, value, async_update)
303
305
  elif key == "timestamp":
304
- self.write_timestamp_data(signal_group, value)
306
+ self.write_timestamp_data(
307
+ signal_group,
308
+ value,
309
+ replace=isinstance(async_update, dict)
310
+ and async_update.get("type") == "replace",
311
+ )
305
312
  else: # pragma: no cover
306
313
  # this should never happen as the keys are fixed in the pydantic model
307
314
  msg = f"Unknown key: {key}. Data will not be written."
@@ -352,7 +359,7 @@ class AsyncWriter(threading.Thread):
352
359
 
353
360
  elif update_type == "replace":
354
361
  # store the data to be written after the scan is complete
355
- self.device_data_replace[signal_group.name] = value
362
+ self.device_data_replace[signal_group.name] = np.asarray(value)
356
363
  else:
357
364
  msg = f"Unknown async update type: {update_type}. Data will not be written."
358
365
  self.connector.raise_alarm(
@@ -444,7 +451,11 @@ class AsyncWriter(threading.Thread):
444
451
 
445
452
  if len(max_shape) != 2:
446
453
  # We currently only support 2D datasets for the 'add_slice' async update type
447
- msg = f"Invalid max_shape for signal group {signal_group.name} async update type 'add_slice': {max_shape}. max_shape cannot exceed two dimensions. Data will not be written."
454
+ msg = (
455
+ f"Invalid max_shape for signal group {signal_group.name} async update type "
456
+ f"'add_slice': {max_shape}. max_shape must have exactly two dimensions. "
457
+ "Data will not be written."
458
+ )
448
459
  self.connector.raise_alarm(
449
460
  severity=Alarms.WARNING,
450
461
  info=messages.ErrorInfo(
@@ -474,43 +485,41 @@ class AsyncWriter(threading.Thread):
474
485
  # if max_shape contains more than one None, we have to use a vlen_dtype
475
486
  num_undefined = sum(1 for i in max_shape if i is None)
476
487
  row_index = async_update["index"]
488
+ if row_index < 0 or (max_shape[0] is not None and row_index >= max_shape[0]):
489
+ msg = (
490
+ f"Invalid row index {row_index} for signal group {signal_group.name}: "
491
+ "'add_slice' updates require a nonnegative row index "
492
+ f"within max_shape {max_shape}. "
493
+ "Data will not be written."
494
+ )
495
+ self.connector.raise_alarm(
496
+ severity=Alarms.WARNING,
497
+ info=messages.ErrorInfo(
498
+ error_message=msg,
499
+ compact_error_message=msg,
500
+ exception_type="ValueError",
501
+ device=signal_group.name,
502
+ ),
503
+ metadata={"scan_id": self.scan_id, "scan_number": self.scan_number},
504
+ )
505
+ return
477
506
 
478
507
  if "value" not in signal_group:
479
508
  if num_undefined > 1:
480
- row_index = 0
481
- shape = (1,) if value.ndim < len(max_shape) else (value.shape[0],)
482
509
  signal_group.create_dataset(
483
510
  "value",
484
- shape=shape,
511
+ shape=(row_index + 1,),
485
512
  maxshape=(None,),
486
513
  dtype=h5py.vlen_dtype(np.dtype(value[0].dtype)),
487
514
  )
488
515
  signal_group["value"][row_index] = value
489
516
  else:
490
- if value.ndim < len(max_shape):
491
- value = value.reshape((1,) + value.shape)
492
- if value.shape[1] > max_shape[1]:
493
- msg = f"Data for {signal_group.name} exceeds the defined max_shape {max_shape}. Data will be truncated."
494
- self.connector.raise_alarm(
495
- severity=Alarms.WARNING,
496
- info=messages.ErrorInfo(
497
- error_message=msg,
498
- compact_error_message=msg,
499
- exception_type="ValueError",
500
- device=signal_group.name,
501
- ),
502
- metadata={"scan_id": self.scan_id, "scan_number": self.scan_number},
503
- )
504
- value = value[:, : max_shape[1]]
505
- create_dataset_safe(signal_group, "value", data=value, maxshape=max_shape)
506
- self.cursor[signal_group.name][row_index] = value.shape[1]
517
+ self._write_initial_fixed_slice(signal_group, value, max_shape, row_index)
507
518
  return
508
519
 
509
520
  # add a slice to the already existing dataset
510
521
  if num_undefined > 1:
511
522
  max_index = signal_group["value"].shape[0]
512
- if row_index == -1:
513
- row_index = max_index + 1
514
523
  if row_index >= max_index:
515
524
  signal_group["value"].resize((row_index + 1,))
516
525
  signal_group["value"][row_index] = value
@@ -532,23 +541,68 @@ class AsyncWriter(threading.Thread):
532
541
  metadata={"scan_id": self.scan_id, "scan_number": self.scan_number},
533
542
  )
534
543
  value = value[: max_shape[1] - col_index]
535
- signal_group["value"].resize((row_index + 1, max_shape[1]))
544
+ signal_group["value"].resize(
545
+ (max(signal_group["value"].shape[0], row_index + 1), max_shape[1])
546
+ )
536
547
  signal_group["value"][row_index, col_index : col_index + len(value)] = value
537
548
  self.cursor[signal_group.name][row_index] = col_index + len(value)
538
549
 
539
- def write_timestamp_data(self, signal_group, value):
550
+ def _write_initial_fixed_slice(
551
+ self,
552
+ signal_group: h5py.Group,
553
+ value: np.ndarray,
554
+ max_shape: list[int | None],
555
+ row_index: int,
556
+ ) -> None:
557
+ """Create a fixed-width slice dataset at the validated initial row index."""
558
+ value = value.reshape((1,) + value.shape)
559
+ if value.shape[1] > max_shape[1]:
560
+ msg = (
561
+ f"Data for {signal_group.name} exceeds the defined max_shape {max_shape}. "
562
+ "Data will be truncated."
563
+ )
564
+ self.connector.raise_alarm(
565
+ severity=Alarms.WARNING,
566
+ info=messages.ErrorInfo(
567
+ error_message=msg,
568
+ compact_error_message=msg,
569
+ exception_type="ValueError",
570
+ device=signal_group.name,
571
+ ),
572
+ metadata={"scan_id": self.scan_id, "scan_number": self.scan_number},
573
+ )
574
+ value = value[:, : max_shape[1]]
575
+ dataset = create_dataset_safe(signal_group, "value", data=value, maxshape=max_shape)
576
+ if row_index > 0:
577
+ # Keep dtype inference from the data and let HDF5 fill the skipped rows.
578
+ dataset.resize((0, value.shape[1]))
579
+ dataset.resize((row_index + 1, value.shape[1]))
580
+ if value.size:
581
+ dataset.write_direct(
582
+ np.ascontiguousarray(value), dest_sel=np.s_[row_index : row_index + 1, :]
583
+ )
584
+ self.cursor[signal_group.name][row_index] = value.shape[1]
585
+
586
+ def write_timestamp_data(
587
+ self, signal_group: h5py.Group, value: Any, replace: bool = False
588
+ ) -> None:
540
589
  """
541
590
  Write the timestamp data to the file.
542
591
  Timestamp data is always written as a 1D array, irrespective of the async update type.
592
+ Replacement updates retain only the latest timestamps.
543
593
 
544
594
  Args:
545
595
  signal_group (h5py.Group): The group to write the data to
546
- value (list): The timestamp data to write
596
+ value (Any): The timestamp data to write
597
+ replace (bool): Whether to replace existing timestamps instead of appending
547
598
  """
548
599
  if not isinstance(value, (list, np.ndarray)):
549
600
  value = [value]
550
601
  if "timestamp" not in signal_group:
551
602
  create_dataset_safe(signal_group, "timestamp", data=value, maxshape=(None,))
603
+ elif replace:
604
+ signal_group["timestamp"].resize((len(value),))
605
+ signal_group["timestamp"][:] = value
552
606
  else:
553
607
  signal_group["timestamp"].resize((len(signal_group["timestamp"]) + len(value),))
554
608
  signal_group["timestamp"][-len(value) :] = value
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "bec-server"
7
- version = "4.0.0"
7
+ version = "4.0.2"
8
8
  description = "BEC server"
9
9
  requires-python = ">=3.11"
10
10
  classifiers = [
@@ -210,6 +210,37 @@ def test_async_writer_add_slice_var_size(async_writer, data):
210
210
  assert out[1].shape == (10,)
211
211
 
212
212
 
213
+ @pytest.mark.parametrize("initial_row", [1, 3])
214
+ @pytest.mark.parametrize("dtype", [np.int16, np.float64])
215
+ def test_async_writer_add_slice_var_size_starts_at_requested_row(
216
+ async_writer, tmp_path, initial_row, dtype
217
+ ):
218
+ """A sparse first vlen row retains its data when earlier rows and more slices arrive."""
219
+ with h5py.File(tmp_path / "initial_vlen_row.h5", "w") as file:
220
+ signal_group = file.create_group("signal")
221
+ async_writer.write_value_data(
222
+ signal_group,
223
+ np.array([7, 8], dtype=dtype),
224
+ {"type": "add_slice", "index": initial_row, "max_shape": [None, None]},
225
+ )
226
+ dataset = signal_group["value"]
227
+ assert dataset.shape == (initial_row + 1,)
228
+ assert h5py.check_vlen_dtype(dataset.dtype) == np.dtype(dtype)
229
+ assert all(row.size == 0 for row in dataset[:initial_row])
230
+ np.testing.assert_array_equal(dataset[initial_row], [7, 8])
231
+
232
+ for row_index, values in [(0, [1, 2]), (initial_row, [9]), (0, [3])]:
233
+ async_writer.write_value_data(
234
+ signal_group,
235
+ np.array(values, dtype=dtype),
236
+ {"type": "add_slice", "index": row_index, "max_shape": [None, None]},
237
+ )
238
+ assert dataset.shape == (initial_row + 1,)
239
+ np.testing.assert_array_equal(dataset[0], [1, 2, 3])
240
+ np.testing.assert_array_equal(dataset[initial_row], [7, 8, 9])
241
+ assert all(row.size == 0 for row in dataset[1:initial_row])
242
+
243
+
213
244
  def test_async_writer_add_slice_var_size_2D_data_warns(async_writer):
214
245
  """
215
246
  Test that adding a slice with 2D data when max_shape is [None, None] raises a warning and skips writing the data.
@@ -271,6 +302,153 @@ def test_async_writer_add_slice_fixed_size(async_writer, data):
271
302
  assert out.shape == (2, 20)
272
303
 
273
304
 
305
+ @pytest.mark.parametrize("max_rows", [None, 4])
306
+ @pytest.mark.parametrize("later_row", [1, 3])
307
+ @pytest.mark.parametrize("earlier_slice", [[3], [3, 4, 5]])
308
+ def test_async_writer_add_slice_fixed_size_preserves_later_rows(
309
+ async_writer, tmp_path, max_rows, later_row, earlier_slice
310
+ ):
311
+ """Interleaved slices preserve rows and append positions, including after truncation."""
312
+ with h5py.File(tmp_path / "interleaved.h5", "w") as file:
313
+ signal_group = file.create_group("signal")
314
+ with mock.patch.object(async_writer.connector, "raise_alarm") as raise_alarm:
315
+ for row_index, values in [(0, [1, 2]), (later_row, [10, 11]), (0, earlier_slice)]:
316
+ async_writer.write_value_data(
317
+ signal_group,
318
+ values,
319
+ {"type": "add_slice", "index": row_index, "max_shape": [max_rows, 4]},
320
+ )
321
+
322
+ expected = np.zeros((later_row + 1, 4), dtype=int)
323
+ row_values = [1, 2] + earlier_slice[:2]
324
+ expected[0, : len(row_values)] = row_values
325
+ expected[later_row, :2] = [10, 11]
326
+ np.testing.assert_array_equal(signal_group["value"][:], expected)
327
+ assert raise_alarm.call_count == (len(earlier_slice) > 2)
328
+
329
+ async_writer.write_value_data(
330
+ signal_group,
331
+ [12, 13],
332
+ {"type": "add_slice", "index": later_row, "max_shape": [max_rows, 4]},
333
+ )
334
+ expected[later_row] = [10, 11, 12, 13]
335
+ np.testing.assert_array_equal(signal_group["value"][:], expected)
336
+
337
+
338
+ @pytest.mark.parametrize("max_rows", [None, 4])
339
+ @pytest.mark.parametrize("initial_values", [[7, 8], [7, 8, 9, 10, 11], []])
340
+ @pytest.mark.parametrize("strided", [False, True])
341
+ def test_async_writer_add_slice_fixed_size_starts_at_requested_row(
342
+ async_writer, tmp_path, max_rows, initial_values, strided
343
+ ):
344
+ """A nonzero first row keeps its data and cursor when earlier rows arrive later."""
345
+ with h5py.File(tmp_path / "initial_row.h5", "w") as file:
346
+ signal_group = file.create_group("signal")
347
+ values = np.asarray(initial_values, dtype=np.int16)
348
+ if strided:
349
+ values = np.repeat(values, 2)[::2]
350
+ async_writer.write_value_data(
351
+ signal_group, values, {"type": "add_slice", "index": 3, "max_shape": [max_rows, 4]}
352
+ )
353
+ expected_initial = np.zeros((4, min(len(initial_values), 4)), dtype=np.int16)
354
+ expected_initial[3] = initial_values[:4]
355
+ np.testing.assert_array_equal(signal_group["value"][:], expected_initial)
356
+ assert signal_group["value"].dtype == np.dtype(np.int16)
357
+
358
+ for row_index, values in [(0, [1, 2]), (3, [12, 13])]:
359
+ async_writer.write_value_data(
360
+ signal_group,
361
+ values,
362
+ {"type": "add_slice", "index": row_index, "max_shape": [max_rows, 4]},
363
+ )
364
+ expected = np.zeros((4, 4), dtype=np.int16)
365
+ expected[0, :2] = [1, 2]
366
+ row_values = (initial_values + [12, 13])[:4]
367
+ expected[3, : len(row_values)] = row_values
368
+ np.testing.assert_array_equal(signal_group["value"][:], expected)
369
+
370
+
371
+ def test_async_writer_add_slice_fixed_size_nonzero_first_row_preserves_string_dtype(
372
+ async_writer, tmp_path
373
+ ):
374
+ """Moving the initial row preserves HDF5's inference of variable-length strings."""
375
+ with h5py.File(tmp_path / "initial_string_row.h5", "w") as file:
376
+ signal_group = file.create_group("signal")
377
+ async_writer.write_value_data(
378
+ signal_group,
379
+ np.array(["a", "bb"], dtype=object),
380
+ {"type": "add_slice", "index": 2, "max_shape": [None, 4]},
381
+ )
382
+ dataset = signal_group["value"]
383
+ np.testing.assert_array_equal(dataset.asstr()[:], [["", ""], ["", ""], ["a", "bb"]])
384
+ assert h5py.check_string_dtype(dataset.dtype).length is None
385
+
386
+
387
+ @pytest.mark.parametrize("cells", [[[1, 2], [3]], [[1, 2], [3, 4]], [[1, 2]], [[], []], [[]]])
388
+ def test_async_writer_add_slice_fixed_size_nonzero_first_row_preserves_vlen_dtype(
389
+ async_writer, tmp_path, cells
390
+ ):
391
+ """HDF5 initializes skipped rows correctly for variable-length numeric values."""
392
+ values = np.empty(len(cells), dtype=h5py.vlen_dtype(np.dtype(np.int32)))
393
+ for index, cell in enumerate(cells):
394
+ values[index] = np.array(cell, dtype=np.int32)
395
+ with h5py.File(tmp_path / "initial_vlen_row.h5", "w") as file:
396
+ signal_group = file.create_group("signal")
397
+ async_writer.write_value_data(
398
+ signal_group, values, {"type": "add_slice", "index": 2, "max_shape": [None, 4]}
399
+ )
400
+ dataset = signal_group["value"]
401
+ assert dataset.shape == (3, len(cells))
402
+ assert h5py.check_vlen_dtype(dataset.dtype) == np.dtype(np.int32)
403
+ assert all(cell.size == 0 for row in dataset[:2] for cell in row)
404
+ for index, value in enumerate(values):
405
+ np.testing.assert_array_equal(dataset[2, index], value)
406
+
407
+
408
+ @pytest.mark.parametrize("populated", [False, True])
409
+ @pytest.mark.parametrize("index, max_rows, row_width", [(-1, None, 4), (4, 4, 4), (-1, None, None)])
410
+ def test_async_writer_add_slice_rejects_invalid_index(
411
+ async_writer, tmp_path, populated, index, max_rows, row_width
412
+ ):
413
+ """An invalid row index cannot overwrite existing rows or initialize an invalid cursor."""
414
+ with h5py.File(tmp_path / "invalid_index.h5", "w") as file:
415
+ signal_group = file.create_group("signal")
416
+ if populated:
417
+ for row_index, values in [(0, [1, 2]), (1, [10, 11])]:
418
+ async_writer.write_value_data(
419
+ signal_group,
420
+ values,
421
+ {"type": "add_slice", "index": row_index, "max_shape": [max_rows, row_width]},
422
+ )
423
+ expected = signal_group["value"][:]
424
+ cursor_before = dict(async_writer.cursor.get(signal_group.name, {}))
425
+
426
+ with mock.patch.object(async_writer.connector, "raise_alarm") as raise_alarm:
427
+ async_writer.write_value_data(
428
+ signal_group,
429
+ [99],
430
+ {"type": "add_slice", "index": index, "max_shape": [max_rows, row_width]},
431
+ )
432
+ raise_alarm.assert_called_once()
433
+ assert raise_alarm.call_args.kwargs["severity"] == Alarms.WARNING
434
+ assert "nonnegative row index" in raise_alarm.call_args.kwargs["info"].error_message
435
+ assert async_writer.cursor.get(signal_group.name, {}) == cursor_before
436
+ if populated:
437
+ assert signal_group["value"].shape == expected.shape
438
+ for actual_row, expected_row in zip(signal_group["value"][:], expected):
439
+ np.testing.assert_array_equal(actual_row, expected_row)
440
+ else:
441
+ assert "value" not in signal_group
442
+
443
+ async_writer.write_value_data(
444
+ signal_group, [3], {"type": "add_slice", "index": 0, "max_shape": [max_rows, row_width]}
445
+ )
446
+ expected_row = [1, 2, 3] if populated else [3]
447
+ if populated and row_width is not None:
448
+ expected_row.append(0)
449
+ np.testing.assert_array_equal(signal_group["value"][0], expected_row)
450
+
451
+
274
452
  def test_async_writer_add_slice_fixed_size_data_consistency(async_writer):
275
453
  endpoint = MessageEndpoints.device_async_readback("scan_id", "monitor_async")
276
454
  data = [
@@ -413,9 +591,65 @@ def test_async_writer_replace(async_writer, data):
413
591
  # read the data back
414
592
  with h5py.File(async_writer.file_path, "r") as f:
415
593
  out = f[async_writer.BASE_PATH]["monitor_async"]["monitor_async"]["value"][:]
594
+ timestamps = f[async_writer.BASE_PATH]["monitor_async"]["monitor_async"]["timestamp"][:]
416
595
 
417
596
  assert out.shape == (10,)
418
597
  assert np.allclose(out, data[-1].signals["monitor_async"]["value"])
598
+ assert np.array_equal(timestamps, [data[-1].signals["monitor_async"]["timestamp"]])
599
+
600
+
601
+ @pytest.mark.parametrize(
602
+ "values",
603
+ [
604
+ (0, 7),
605
+ (0.0, 1.2),
606
+ (False, True),
607
+ (np.int64(0), np.int64(7)),
608
+ (np.float64(0.0), np.float64(1.2)),
609
+ ],
610
+ )
611
+ def test_async_writer_replace_scalar(async_writer, values):
612
+ """Write only the latest scalar value and timestamp after scan completion."""
613
+ for timestamp, value in enumerate(values, start=1):
614
+ message = messages.DeviceMessage(
615
+ signals={"monitor_async": {"value": value, "timestamp": float(timestamp)}},
616
+ metadata={"async_update": {"type": "replace"}},
617
+ )
618
+ async_writer.write_data({"monitor_async": [message]})
619
+
620
+ group = async_writer.file_handle[f"{async_writer.BASE_PATH}/monitor_async/monitor_async"]
621
+ try:
622
+ assert "value" not in group
623
+ async_writer.write_data({}, write_replace=True)
624
+ assert group["value"].shape == ()
625
+ assert group["value"][()] == values[-1]
626
+ assert np.array_equal(group["timestamp"][:], [2.0])
627
+ finally:
628
+ async_writer.file_handle.close()
629
+
630
+
631
+ @pytest.mark.parametrize("update_type", ["replace", "add", "add_slice"])
632
+ @pytest.mark.parametrize("timestamps", [[1, 2, 3], [1]])
633
+ def test_async_writer_timestamp_aggregation(async_writer, update_type, timestamps):
634
+ """Keep replacement timestamps together and preserve append behavior for other updates."""
635
+ metadata = {"type": update_type}
636
+ if update_type == "add":
637
+ metadata["max_shape"] = [None]
638
+ elif update_type == "add_slice":
639
+ metadata.update(max_shape=[None, None], index=0)
640
+
641
+ for timestamp in (timestamps, [4, 5]):
642
+ message = messages.DeviceMessage(
643
+ signals={"monitor_async": {"value": np.array([6, 7]), "timestamp": timestamp}},
644
+ metadata={"async_update": metadata},
645
+ )
646
+ async_writer.write_data({"monitor_async": [message]})
647
+ async_writer.write_data({}, write_replace=True)
648
+
649
+ group = async_writer.file_handle[f"{async_writer.BASE_PATH}/monitor_async/monitor_async"]
650
+ expected = [4, 5] if update_type == "replace" else timestamps + [4, 5]
651
+ assert np.array_equal(group["timestamp"][:], expected)
652
+ async_writer.file_handle.close()
419
653
 
420
654
 
421
655
  def test_async_writer_async_signal(async_writer):
File without changes
File without changes
File without changes