bec-server 2.4.2__tar.gz → 2.6.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 (125) hide show
  1. bec_server-2.6.0/.gitignore +180 -0
  2. bec_server-2.6.0/PKG-INFO +32 -0
  3. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/devices/devicemanager.py +3 -31
  4. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/__init__.py +1 -1
  5. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/cli/launch.py +0 -3
  6. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/file_writer.py +12 -105
  7. bec_server-2.6.0/bec_server/file_writer_plugins/__init__.py +1 -0
  8. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_manager.py +11 -30
  9. bec_server-2.6.0/pyproject.toml +62 -0
  10. bec_server-2.6.0/tests/tests_bec_server_utils/test_main.py +68 -0
  11. bec_server-2.6.0/tests/tests_bec_server_utils/test_service_handler.py +64 -0
  12. bec_server-2.6.0/tests/tests_bec_server_utils/test_tmux_launch.py +47 -0
  13. bec_server-2.6.0/tests/tests_data_processing/conftest.py +12 -0
  14. bec_server-2.6.0/tests/tests_data_processing/test_dap_cli_launch.py +40 -0
  15. bec_server-2.6.0/tests/tests_data_processing/test_dap_server.py +13 -0
  16. bec_server-2.6.0/tests/tests_data_processing/test_dap_service_manager.py +115 -0
  17. bec_server-2.6.0/tests/tests_data_processing/test_lmfit1d_service.py +164 -0
  18. bec_server-2.6.0/tests/tests_device_server/conftest.py +24 -0
  19. bec_server-2.6.0/tests/tests_device_server/test_config_handler.py +109 -0
  20. bec_server-2.6.0/tests/tests_device_server/test_device_manager_ds.py +174 -0
  21. bec_server-2.6.0/tests/tests_device_server/test_device_serializer.py +45 -0
  22. bec_server-2.6.0/tests/tests_device_server/test_device_server.py +814 -0
  23. bec_server-2.6.0/tests/tests_device_server/test_device_server_cli_launch.py +32 -0
  24. bec_server-2.6.0/tests/tests_device_server/test_rpc_mixin.py +255 -0
  25. bec_server-2.6.0/tests/tests_file_writer/conftest.py +12 -0
  26. bec_server-2.6.0/tests/tests_file_writer/test_file_writer.py +165 -0
  27. bec_server-2.6.0/tests/tests_file_writer/test_file_writer_cli_launch.py +32 -0
  28. bec_server-2.6.0/tests/tests_file_writer/test_file_writer_manager.py +284 -0
  29. bec_server-2.6.0/tests/tests_scan_bundler/conftest.py +51 -0
  30. bec_server-2.6.0/tests/tests_scan_bundler/test_bec_emitter.py +65 -0
  31. bec_server-2.6.0/tests/tests_scan_bundler/test_bluesky_emitter.py +78 -0
  32. bec_server-2.6.0/tests/tests_scan_bundler/test_emitter.py +104 -0
  33. bec_server-2.6.0/tests/tests_scan_bundler/test_scan_bundler.py +664 -0
  34. bec_server-2.6.0/tests/tests_scan_bundler/test_scan_bundler_cli_launch.py +32 -0
  35. bec_server-2.6.0/tests/tests_scan_server/conftest.py +12 -0
  36. bec_server-2.6.0/tests/tests_scan_server/test_flomni_fermat_scan.py +61 -0
  37. bec_server-2.6.0/tests/tests_scan_server/test_path_optimization.py +230 -0
  38. bec_server-2.6.0/tests/tests_scan_server/test_scan_guard.py +307 -0
  39. bec_server-2.6.0/tests/tests_scan_server/test_scan_server_cli_launch.py +32 -0
  40. bec_server-2.6.0/tests/tests_scan_server/test_scan_server_queue.py +696 -0
  41. bec_server-2.6.0/tests/tests_scan_server/test_scan_stubs.py +123 -0
  42. bec_server-2.6.0/tests/tests_scan_server/test_scan_worker.py +1520 -0
  43. bec_server-2.6.0/tests/tests_scan_server/test_scans.py +2703 -0
  44. bec_server-2.6.0/tests/tests_scan_server/utils.py +118 -0
  45. bec_server-2.6.0/tests/tests_scihub/conftest.py +12 -0
  46. bec_server-2.6.0/tests/tests_scihub/test_repeated_timer.py +32 -0
  47. bec_server-2.6.0/tests/tests_scihub/test_scibec_config_handler.py +352 -0
  48. bec_server-2.6.0/tests/tests_scihub/test_scibec_connector.py +151 -0
  49. bec_server-2.6.0/tests/tests_scihub/test_scibec_metadata_handler.py +213 -0
  50. bec_server-2.6.0/tests/tests_scihub/test_scihub_cli_launch.py +32 -0
  51. bec_server-2.6.0/tests/tests_scihub/test_scilog_connector.py +40 -0
  52. bec-server-2.4.2/PKG-INFO +0 -12
  53. bec-server-2.4.2/bec_server/file_writer_plugins/__init__.py +0 -2
  54. bec-server-2.4.2/bec_server.egg-info/PKG-INFO +0 -12
  55. bec-server-2.4.2/bec_server.egg-info/SOURCES.txt +0 -78
  56. bec-server-2.4.2/bec_server.egg-info/dependency_links.txt +0 -1
  57. bec-server-2.4.2/bec_server.egg-info/entry_points.txt +0 -8
  58. bec-server-2.4.2/bec_server.egg-info/requires.txt +0 -24
  59. bec-server-2.4.2/bec_server.egg-info/top_level.txt +0 -1
  60. bec-server-2.4.2/setup.cfg +0 -26
  61. bec-server-2.4.2/setup.py +0 -52
  62. {bec-server-2.4.2 → bec_server-2.6.0}/README.md +0 -0
  63. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/__init__.py +0 -0
  64. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/bec_server_utils/__init__.py +0 -0
  65. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/bec_server_utils/launch.py +0 -0
  66. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/bec_server_utils/service_handler.py +0 -0
  67. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/bec_server_utils/subprocess_launch.py +0 -0
  68. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/bec_server_utils/tmux_launch.py +0 -0
  69. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/__init__.py +0 -0
  70. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/cli/__init__.py +0 -0
  71. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/cli/launch.py +0 -0
  72. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/dap_server.py +0 -0
  73. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/dap_service.py +0 -0
  74. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/dap_service_manager.py +0 -0
  75. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/data_processing/lmfit1d_service.py +0 -0
  76. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/__init__.py +0 -0
  77. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/cli/__init__.py +0 -0
  78. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/cli/launch.py +0 -0
  79. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/device_server.py +0 -0
  80. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/devices/__init__.py +0 -0
  81. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/devices/config_update_handler.py +0 -0
  82. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/devices/device_serializer.py +0 -0
  83. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/device_server/rpc_mixin.py +0 -0
  84. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/cli/__init__.py +0 -0
  85. {bec-server-2.4.2/bec_server/file_writer_plugins → bec_server-2.6.0/bec_server/file_writer}/default_writer.py +0 -0
  86. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/file_writer_manager.py +0 -0
  87. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer/merged_dicts.py +0 -0
  88. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/file_writer_plugins/cSAXS.py +0 -0
  89. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/__init__.py +0 -0
  90. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/bec_emitter.py +0 -0
  91. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/bluesky_emitter.py +0 -0
  92. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/cli/__init__.py +0 -0
  93. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/cli/launch.py +0 -0
  94. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/emitter.py +0 -0
  95. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_bundler/scan_bundler.py +0 -0
  96. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/__init__.py +0 -0
  97. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/cli/__init__.py +0 -0
  98. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/cli/launch.py +0 -0
  99. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/device_validation.py +0 -0
  100. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/errors.py +0 -0
  101. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/path_optimization.py +0 -0
  102. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_assembler.py +0 -0
  103. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_guard.py +0 -0
  104. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/LamNIFermatScan.py +0 -0
  105. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/__init__.py +0 -0
  106. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/flomni_fermat_scan.py +0 -0
  107. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/otf_scan.py +0 -0
  108. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/owis_grid.py +0 -0
  109. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_plugins/sgalil_grid.py +0 -0
  110. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_queue.py +0 -0
  111. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_server.py +0 -0
  112. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_stubs.py +0 -0
  113. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scan_worker.py +0 -0
  114. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scan_server/scans.py +0 -0
  115. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/__init__.py +0 -0
  116. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/cli/__init__.py +0 -0
  117. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/cli/launch.py +0 -0
  118. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/repeated_timer.py +0 -0
  119. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scibec/__init__.py +0 -0
  120. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scibec/config_handler.py +0 -0
  121. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scibec/scibec_connector.py +0 -0
  122. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scibec/scibec_metadata_handler.py +0 -0
  123. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scihub.py +0 -0
  124. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scilog/__init__.py +0 -0
  125. {bec-server-2.4.2 → bec_server-2.6.0}/bec_server/scihub/scilog/scilog.py +0 -0
@@ -0,0 +1,180 @@
1
+ **/*_venv
2
+ **/.idea
3
+ *.log
4
+ **/__pycache__
5
+ **/.DS_Store
6
+ **/out
7
+ **/.vscode
8
+ **/.pytest_cache
9
+ **/*.egg*
10
+
11
+ # recovery_config files
12
+ recovery_config_*
13
+
14
+ # file writer data
15
+ **.h5
16
+
17
+ # Byte-compiled / optimized / DLL files
18
+ __pycache__/
19
+ *.py[cod]
20
+ *$py.class
21
+
22
+ # C extensions
23
+ *.so
24
+
25
+ # Distribution / packaging
26
+ .Python
27
+ build/
28
+ develop-eggs/
29
+ dist/
30
+ downloads/
31
+ eggs/
32
+ .eggs/
33
+ lib/
34
+ lib64/
35
+ parts/
36
+ sdist/
37
+ var/
38
+ wheels/
39
+ share/python-wheels/
40
+ *.egg-info/
41
+ .installed.cfg
42
+ *.egg
43
+ MANIFEST
44
+
45
+ # PyInstaller
46
+ # Usually these files are written by a python script from a template
47
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
48
+ *.manifest
49
+ *.spec
50
+
51
+ # Installer logs
52
+ pip-log.txt
53
+ pip-delete-this-directory.txt
54
+
55
+ # Unit test / coverage reports
56
+ htmlcov/
57
+ .tox/
58
+ .nox/
59
+ .coverage
60
+ .coverage.*
61
+ .cache
62
+ nosetests.xml
63
+ coverage.xml
64
+ *.cover
65
+ *.py,cover
66
+ .hypothesis/
67
+ .pytest_cache/
68
+ cover/
69
+
70
+ # Translations
71
+ *.mo
72
+ *.pot
73
+
74
+ # Django stuff:
75
+ *.log
76
+ local_settings.py
77
+ db.sqlite3
78
+ db.sqlite3-journal
79
+
80
+ # Flask stuff:
81
+ instance/
82
+ .webassets-cache
83
+
84
+ # Scrapy stuff:
85
+ .scrapy
86
+
87
+ # Sphinx documentation
88
+ docs/**/_build/
89
+ docs/**/autodoc/
90
+ docs/**/_autosummary/
91
+
92
+ # PyBuilder
93
+ .pybuilder/
94
+ target/
95
+
96
+ # Jupyter Notebook
97
+ .ipynb_checkpoints
98
+
99
+ # IPython
100
+ profile_default/
101
+ ipython_config.py
102
+
103
+ **.prof
104
+
105
+ # pyenv
106
+ # For a library or package, you might want to ignore these files since the code is
107
+ # intended to run in multiple environments; otherwise, check them in:
108
+ # .python-version
109
+
110
+ # pipenv
111
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
112
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
113
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
114
+ # install all needed dependencies.
115
+ #Pipfile.lock
116
+
117
+ # poetry
118
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
119
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
120
+ # commonly ignored for libraries.
121
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
122
+ #poetry.lock
123
+
124
+ # pdm
125
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
126
+ #pdm.lock
127
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
128
+ # in version control.
129
+ # https://pdm.fming.dev/#use-with-ide
130
+ .pdm.toml
131
+
132
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
133
+ __pypackages__/
134
+
135
+ # Celery stuff
136
+ celerybeat-schedule
137
+ celerybeat.pid
138
+
139
+ # SageMath parsed files
140
+ *.sage.py
141
+
142
+ # Environments
143
+ .env
144
+ .venv
145
+ env/
146
+ venv/
147
+ ENV/
148
+ env.bak/
149
+ venv.bak/
150
+
151
+ # Spyder project settings
152
+ .spyderproject
153
+ .spyproject
154
+
155
+ # Rope project settings
156
+ .ropeproject
157
+
158
+ # mkdocs documentation
159
+ /site
160
+
161
+ # mypy
162
+ .mypy_cache/
163
+ .dmypy.json
164
+ dmypy.json
165
+
166
+ # Pyre type checker
167
+ .pyre/
168
+
169
+ # pytype static type analyzer
170
+ .pytype/
171
+
172
+ # Cython debug symbols
173
+ cython_debug/
174
+
175
+ # PyCharm
176
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
177
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
178
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
179
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
180
+ #.idea/
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.3
2
+ Name: bec-server
3
+ Version: 2.6.0
4
+ Summary: BEC server
5
+ Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec/issues
6
+ Project-URL: Homepage, https://gitlab.psi.ch/bec/bec
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Topic :: Scientific/Engineering
10
+ Requires-Python: >=3.10
11
+ Requires-Dist: bec-lib
12
+ Requires-Dist: cytoolz
13
+ Requires-Dist: h5py
14
+ Requires-Dist: libtmux
15
+ Requires-Dist: lmfit
16
+ Requires-Dist: msgpack
17
+ Requires-Dist: numpy
18
+ Requires-Dist: ophyd
19
+ Requires-Dist: ophyd-devices
20
+ Requires-Dist: py-scibec
21
+ Requires-Dist: pydantic
22
+ Requires-Dist: python-dotenv
23
+ Requires-Dist: pyyaml
24
+ Requires-Dist: rich
25
+ Provides-Extra: dev
26
+ Requires-Dist: black; extra == 'dev'
27
+ Requires-Dist: coverage; extra == 'dev'
28
+ Requires-Dist: isort; extra == 'dev'
29
+ Requires-Dist: pylint; extra == 'dev'
30
+ Requires-Dist: pytest; extra == 'dev'
31
+ Requires-Dist: pytest-random-order; extra == 'dev'
32
+ Requires-Dist: pytest-timeout; extra == 'dev'
@@ -13,7 +13,6 @@ from functools import reduce
13
13
 
14
14
  import numpy as np
15
15
  import ophyd
16
- import ophyd.sim as ops
17
16
  import ophyd_devices as opd
18
17
  from ophyd.ophydobj import OphydObject
19
18
  from ophyd.signal import EpicsSignalBase
@@ -27,16 +26,11 @@ from bec_lib import (
27
26
  MessageEndpoints,
28
27
  bec_logger,
29
28
  messages,
29
+ plugin_helper,
30
30
  )
31
31
  from bec_server.device_server.devices.config_update_handler import ConfigUpdateHandler
32
32
  from bec_server.device_server.devices.device_serializer import get_device_info
33
33
 
34
- try:
35
- from bec_plugins import devices as plugin_devices
36
- except ImportError:
37
- plugin_devices = None
38
-
39
-
40
34
  logger = bec_logger.logger
41
35
 
42
36
 
@@ -118,30 +112,8 @@ class DeviceManagerDS(DeviceManagerBase):
118
112
 
119
113
  @staticmethod
120
114
  def _get_device_class(dev_type: str) -> type:
121
- """
122
- Return the class object from 'dev_type' string in the form '[module:][submodule:]class_name'
123
- The class is looked after in ophyd devices[.module][.submodule] first, if it is not
124
- present plugin_devices, ophyd, ophyd_devices.sim are searched too
125
-
126
- Args:
127
- dev_type (str): device type string
128
-
129
- Returns:
130
- type: class object
131
- """
132
- submodule, _, class_name = dev_type.rpartition(":")
133
- if submodule:
134
- submodule = f".{submodule.replace(':', '.')}"
135
- for parent_module in (opd, plugin_devices, ophyd, ops):
136
- try:
137
- module = __import__(f"{parent_module.__name__}{submodule}", fromlist=[""])
138
- except ModuleNotFoundError:
139
- continue
140
- else:
141
- break
142
- else:
143
- raise TypeError(f"Unknown device class {dev_type}")
144
- return getattr(module, class_name)
115
+ """Get the device class from the device type"""
116
+ return plugin_helper.get_plugin_class(dev_type, [opd, ophyd])
145
117
 
146
118
  def _load_session(self, *_args, **_kwargs):
147
119
  delayed_init = []
@@ -1,3 +1,3 @@
1
1
  from .cli.launch import main
2
- from .file_writer import NexusFileWriter, NeXusFileXMLWriter
2
+ from .file_writer import NexusFileWriter
3
3
  from .file_writer_manager import FileWriterManager
@@ -23,9 +23,6 @@ def main():
23
23
  config = ServiceConfig(config_path)
24
24
 
25
25
  file_writer_manager = file_writer.FileWriterManager(config, RedisConnector)
26
- file_writer_manager.file_writer.configure(
27
- layout_file=os.path.abspath("./layout_cSAXS_NXsas.xml")
28
- )
29
26
  try:
30
27
  event = threading.Event()
31
28
  logger.success("Started FileWriter")
@@ -8,11 +8,10 @@ import traceback
8
8
  import typing
9
9
 
10
10
  import h5py
11
- import xmltodict
12
11
 
13
- import bec_server.file_writer_plugins as fwp
14
- from bec_lib import MessageEndpoints, bec_logger, messages
12
+ from bec_lib import MessageEndpoints, bec_logger, messages, plugin_helper
15
13
 
14
+ from .default_writer import NeXus_format as default_NeXus_format
16
15
  from .merged_dicts import merge_dicts
17
16
 
18
17
  logger = bec_logger.logger
@@ -49,107 +48,6 @@ class FileWriter(abc.ABC):
49
48
  return device_storage
50
49
 
51
50
 
52
- class XMLWriter:
53
- @staticmethod
54
- def get_type(type_string: str):
55
- if type_string == "float":
56
- return float
57
- if type_string == "string":
58
- return str
59
- if type_string == "int":
60
- return int
61
- raise NeXusLayoutError(f"Unsupported data type {type_string}.")
62
-
63
- def get_value(self, value, entry, source, data_type):
64
- if source == "constant":
65
- if data_type:
66
- return self.get_type(data_type)(value)
67
- return value
68
- return entry
69
-
70
- def add_group(self, container, val):
71
- name = val.pop("@name")
72
- group = container.create_group(name)
73
- self.add_content(group, val)
74
-
75
- def add_dataset(self, container, val):
76
- name = val.pop("@name")
77
- source = val.pop("@source")
78
- value = val.pop("@value", None)
79
- data_type = val.pop("@type", None)
80
- entry = val.pop("@entry", None)
81
-
82
- data = self.get_value(value=value, entry=entry, source=source, data_type=data_type)
83
- if data is None:
84
- return
85
- dataset = container.create_dataset(name, data=data)
86
- self.add_content(dataset, val)
87
- return
88
-
89
- def add_attribute(self, container, val):
90
- name = val.pop("@name")
91
- source = val.pop("@source")
92
- value = val.pop("@value", None)
93
- data_type = val.pop("@type", None)
94
- entry = val.pop("@entry", None)
95
-
96
- data = self.get_value(value=value, entry=entry, source=source, data_type=data_type)
97
- setattr(container.attrs, name, data)
98
-
99
- def add_hardlink(self, container, val):
100
- pass
101
-
102
- def add_softlink(self, container, val):
103
- pass
104
-
105
- def add_content(self, container, layout):
106
- for key, values in layout.items():
107
- if not isinstance(values, list):
108
- values = [values]
109
- for val in values:
110
- if key == "group":
111
- self.add_group(container, val)
112
- elif key == "hdf5_layout":
113
- self.add_base_entry(container, val)
114
- elif key == "attribute":
115
- self.add_attribute(container, val)
116
- elif key == "dataset":
117
- self.add_dataset(container, val)
118
- elif key == "hardlink":
119
- self.add_hardlink(container, val)
120
- elif key == "softlink":
121
- self.add_softlink(container, val)
122
- else:
123
- pass
124
- # raise NeXusLayoutError()
125
-
126
- def add_base_entry(self, container, val):
127
- self.add_group(container, val["group"])
128
-
129
-
130
- class NeXusFileXMLWriter(FileWriter, XMLWriter):
131
- def configure(self, layout_file, **kwargs):
132
- self.layout_file = layout_file
133
- with open(self.layout_file, "br") as f:
134
- self.layout = xmltodict.parse(f)
135
-
136
- def get_value(self, value, entry, source, data_type):
137
- if source == "constant":
138
- if data_type:
139
- return self.get_type(data_type)(value)
140
- return value
141
- if source == "bec":
142
- return self.data.get(entry)
143
- return entry
144
-
145
- def write(self, file_path: str, data):
146
- print(f"writing file to {file_path}")
147
- self.data = self._create_device_data_storage(data)
148
-
149
- with h5py.File(file_path, "w") as file:
150
- self.add_content(file, self.layout)
151
-
152
-
153
51
  class HDF5Storage:
154
52
  """
155
53
  The HDF5Storage class is a container used by the HDF5 writer plugins to store data in the correct NeXus format.
@@ -310,7 +208,16 @@ class NexusFileWriter(FileWriter):
310
208
  ).isoformat()
311
209
  if data.end_time is not None:
312
210
  device_storage["end_time"] = datetime.datetime.fromtimestamp(data.end_time).isoformat()
313
- writer_format = getattr(fwp, self.file_writer_manager.file_writer_config.get("plugin"))
211
+
212
+ requested_plugin = self.file_writer_manager.file_writer_config.get("plugin")
213
+ if requested_plugin == "default_NeXus_format":
214
+ writer_format = default_NeXus_format
215
+ else:
216
+ plugins = plugin_helper.get_file_writer_plugins()
217
+ if requested_plugin not in plugins:
218
+ logger.error(f"Plugin {requested_plugin} not found. Using default plugin.")
219
+ writer_format = default_NeXus_format
220
+
314
221
  for file_ref in data.file_references.values():
315
222
  rel_path = os.path.relpath(file_ref["path"], os.path.dirname(file_path))
316
223
  file_ref["path"] = rel_path
@@ -0,0 +1 @@
1
+ from .cSAXS import NeXus_format as cSAXS_NeXus_format
@@ -1,11 +1,6 @@
1
- import glob
2
- import importlib
3
- import importlib.util
4
1
  import inspect
5
- import os
6
- from pathlib import Path
7
2
 
8
- from bec_lib import MessageEndpoints, bec_logger
3
+ from bec_lib import MessageEndpoints, bec_logger, plugin_helper
9
4
  from bec_lib.messages import AvailableResourceMessage
10
5
  from bec_lib.signature_serializer import signature_to_dict
11
6
 
@@ -15,7 +10,6 @@ logger = bec_logger.logger
15
10
 
16
11
 
17
12
  class ScanManager:
18
- DEFAULT_PLUGIN_PATH = Path(os.path.dirname(os.path.abspath(__file__)) + "/../../").resolve()
19
13
 
20
14
  def __init__(self, *, parent):
21
15
  """
@@ -31,30 +25,17 @@ class ScanManager:
31
25
 
32
26
  def load_plugins(self):
33
27
  """load scan plugins"""
34
- plugin_path = os.environ.get("BEC_PLUGIN_PATH")
35
- if not plugin_path:
36
- logger.info("BEC_PLUGIN_PATH not set. Using default plugin path.")
37
- plugin_path = self.DEFAULT_PLUGIN_PATH
38
- else:
39
- logger.info(f"Using plugin path {plugin_path}")
40
- plugin_path = os.path.join(plugin_path, "scan_server/scan_plugins")
41
- files = glob.glob(os.path.join(plugin_path, "*.py"))
42
- for file in files:
43
- if file.endswith("__init__.py"):
28
+ plugins = plugin_helper.get_scan_plugins()
29
+ if not plugins:
30
+ return
31
+ for name, cls in plugins.items():
32
+ if not issubclass(cls, ScanServerScans.RequestBase):
33
+ logger.error(
34
+ f"Plugin {name} is not a valid scan plugin as it does not inherit from RequestBase. Skipping."
35
+ )
44
36
  continue
45
- module_spec = importlib.util.spec_from_file_location("scan_plugins", file)
46
- plugin_module = importlib.util.module_from_spec(module_spec)
47
- module_spec.loader.exec_module(plugin_module)
48
- module_members = inspect.getmembers(plugin_module)
49
- for name, cls in module_members:
50
- if not inspect.isclass(cls):
51
- continue
52
- # ignore imported classes
53
- if cls.__module__ != "scan_plugins":
54
- continue
55
- if issubclass(cls, ScanServerScans.RequestBase):
56
- self._plugins[name] = cls
57
- logger.info(f"Loading scan plugin {name}")
37
+ self._plugins[name] = cls
38
+ logger.info(f"Loading scan plugin {name}")
58
39
 
59
40
  def update_available_scans(self):
60
41
  """load all scans and plugin scans"""
@@ -0,0 +1,62 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "bec-server"
7
+ version = "2.6.0"
8
+ description = "BEC server"
9
+ requires-python = ">=3.10"
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Programming Language :: Python :: 3",
13
+ "Topic :: Scientific/Engineering",
14
+ ]
15
+ dependencies = [
16
+ "bec-lib",
17
+ "cytoolz",
18
+ "h5py",
19
+ "libtmux",
20
+ "lmfit",
21
+ "msgpack",
22
+ "numpy",
23
+ "ophyd",
24
+ "ophyd_devices",
25
+ "pydantic",
26
+ "py-scibec",
27
+ "pyyaml",
28
+ "python-dotenv",
29
+ "rich",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = [
34
+ "black",
35
+ "isort",
36
+ "coverage",
37
+ "pylint",
38
+ "pytest",
39
+ "pytest-random-order",
40
+ "pytest-timeout",
41
+ ]
42
+
43
+ [project.scripts]
44
+ bec-dap = "bec_server.data_processing:main"
45
+ bec-device-server = "bec_server.device_server:main"
46
+ bec-file-writer = "bec_server.file_writer:main"
47
+ bec-scan-server = "bec_server.scan_server:main"
48
+ bec-scan-bundler = "bec_server.scan_bundler:main"
49
+ bec-scihub = "bec_server.scihub:main"
50
+ bec-server = "bec_server:main"
51
+
52
+
53
+ [project.urls]
54
+ "Bug Tracker" = "https://gitlab.psi.ch/bec/bec/issues"
55
+ Homepage = "https://gitlab.psi.ch/bec/bec"
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ include = ["*"]
59
+
60
+ [tool.black]
61
+ line-length = 100
62
+ skip-magic-trailing-comma = true
@@ -0,0 +1,68 @@
1
+ from unittest import mock
2
+
3
+ from bec_server.bec_server_utils.launch import main
4
+
5
+
6
+ def test_main_start():
7
+ with mock.patch("bec_server.bec_server_utils.launch.ServiceHandler") as mock_service_handler:
8
+ with mock.patch("bec_server.bec_server_utils.launch.argparse") as mock_argparse:
9
+ mock_argparse.ArgumentParser().parse_args.return_value = mock.MagicMock(
10
+ command="start", config=None
11
+ )
12
+ main()
13
+ mock_service_handler.assert_called_once_with(
14
+ bec_path=mock.ANY, config_path=None, no_tmux=False
15
+ )
16
+ mock_service_handler().start.assert_called_once()
17
+
18
+
19
+ def test_main_stop():
20
+ with mock.patch("bec_server.bec_server_utils.launch.ServiceHandler") as mock_service_handler:
21
+ with mock.patch("bec_server.bec_server_utils.launch.argparse") as mock_argparse:
22
+ mock_argparse.ArgumentParser().parse_args.return_value = mock.MagicMock(
23
+ command="stop", config=None
24
+ )
25
+ main()
26
+ mock_service_handler.assert_called_once_with(
27
+ bec_path=mock.ANY, config_path=None, no_tmux=False
28
+ )
29
+ mock_service_handler().stop.assert_called_once()
30
+
31
+
32
+ def test_main_restart():
33
+ with mock.patch("bec_server.bec_server_utils.launch.ServiceHandler") as mock_service_handler:
34
+ with mock.patch("bec_server.bec_server_utils.launch.argparse") as mock_argparse:
35
+ mock_argparse.ArgumentParser().parse_args.return_value = mock.MagicMock(
36
+ command="restart", config=None
37
+ )
38
+ main()
39
+ mock_service_handler.assert_called_once_with(
40
+ bec_path=mock.ANY, config_path=None, no_tmux=False
41
+ )
42
+ mock_service_handler().restart.assert_called_once()
43
+
44
+
45
+ def test_main_start_with_config():
46
+ with mock.patch("bec_server.bec_server_utils.launch.ServiceHandler") as mock_service_handler:
47
+ with mock.patch("bec_server.bec_server_utils.launch.argparse") as mock_argparse:
48
+ mock_argparse.ArgumentParser().parse_args.return_value = mock.MagicMock(
49
+ command="start", config="/path/to/config"
50
+ )
51
+ main()
52
+ mock_service_handler.assert_called_once_with(
53
+ bec_path=mock.ANY, config_path="/path/to/config", no_tmux=False
54
+ )
55
+ mock_service_handler().start.assert_called_once()
56
+
57
+
58
+ def test_main_restart_with_config():
59
+ with mock.patch("bec_server.bec_server_utils.launch.ServiceHandler") as mock_service_handler:
60
+ with mock.patch("bec_server.bec_server_utils.launch.argparse") as mock_argparse:
61
+ mock_argparse.ArgumentParser().parse_args.return_value = mock.MagicMock(
62
+ command="restart", config="/path/to/config"
63
+ )
64
+ main()
65
+ mock_service_handler.assert_called_once_with(
66
+ bec_path=mock.ANY, config_path="/path/to/config", no_tmux=False
67
+ )
68
+ mock_service_handler().restart.assert_called_once()
@@ -0,0 +1,64 @@
1
+ from unittest import mock
2
+
3
+ from bec_server.bec_server_utils.service_handler import ServiceHandler
4
+
5
+
6
+ def test_service_handler():
7
+ bec_path = "/path/to/bec"
8
+ config_path = "/path/to/config"
9
+
10
+ with mock.patch("bec_server.bec_server_utils.service_handler.sys") as mock_sys:
11
+ mock_sys.platform = "linux"
12
+ service_handler = ServiceHandler(bec_path, config_path)
13
+ assert service_handler.interface == "tmux"
14
+
15
+
16
+ def test_service_handler_start():
17
+ bec_path = "/path/to/bec"
18
+ config_path = "/path/to/config"
19
+
20
+ with mock.patch("bec_server.bec_server_utils.service_handler.sys") as mock_sys:
21
+ mock_sys.platform = "linux"
22
+ service_handler = ServiceHandler(bec_path, config_path)
23
+
24
+ with mock.patch(
25
+ "bec_server.bec_server_utils.service_handler.tmux_start"
26
+ ) as mock_tmux_start:
27
+ service_handler.start()
28
+ mock_tmux_start.assert_called_once_with(bec_path, config_path, service_handler.SERVICES)
29
+
30
+
31
+ def test_service_handler_stop():
32
+ with mock.patch("bec_server.bec_server_utils.service_handler.tmux_stop") as mock_tmux_stop:
33
+ service_handler = ServiceHandler("/path/to/bec", "/path/to/config")
34
+ service_handler.stop()
35
+ mock_tmux_stop.assert_called_once()
36
+
37
+
38
+ def test_service_handler_restart():
39
+ bec_path = "/path/to/bec"
40
+ config_path = "/path/to/config"
41
+
42
+ with mock.patch("bec_server.bec_server_utils.service_handler.sys") as mock_sys:
43
+ mock_sys.platform = "linux"
44
+ service_handler = ServiceHandler(bec_path, config_path)
45
+
46
+ with mock.patch("bec_server.bec_server_utils.service_handler.tmux_stop") as mock_tmux_stop:
47
+ with mock.patch(
48
+ "bec_server.bec_server_utils.service_handler.tmux_start"
49
+ ) as mock_tmux_start:
50
+ service_handler.restart()
51
+ mock_tmux_stop.assert_called_once()
52
+ mock_tmux_start.assert_called_once_with(
53
+ bec_path, config_path, service_handler.SERVICES
54
+ )
55
+
56
+
57
+ def test_service_handler_services():
58
+ service_handler = ServiceHandler("/path/to/bec", "/path/to/config")
59
+ assert (
60
+ service_handler.SERVICES["scan_server"]["path"].substitute(base_path="/path/to/bec")
61
+ == "/path/to/bec/scan_server"
62
+ )
63
+
64
+ assert service_handler.SERVICES["scan_server"]["command"] == "bec-scan-server"