cgse-common 2025.0.4__tar.gz → 2025.0.6__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.
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/PKG-INFO +1 -1
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/pyproject.toml +7 -3
- cgse_common-2025.0.6/src/cgse_common/__init__.py +0 -0
- {cgse_common-2025.0.4/src/egse → cgse_common-2025.0.6/src/cgse_common}/settings.yaml +4 -1
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/control.py +0 -1
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/decorators.py +13 -4
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/env.py +223 -37
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/plugin.py +68 -6
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/protocol.py +1 -1
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/response.py +2 -1
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/services.py +4 -1
- cgse_common-2025.0.6/src/egse/settings.py +448 -0
- cgse_common-2025.0.6/src/egse/settings.yaml +5 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/setup.py +49 -26
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/system.py +23 -17
- cgse_common-2025.0.4/src/egse/settings.py +0 -381
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/.gitignore +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/README.md +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/bits.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/calibration.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/command.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/config.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/device.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/exceptions.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/hk.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/metrics.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/mixin.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/monitoring.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/observer.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/obsid.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/persistence.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/process.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/proxy.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/reload.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/resource.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/services.yaml +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/state.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/version.py +0 -0
- {cgse_common-2025.0.4 → cgse_common-2025.0.6}/src/egse/zmq_ser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cgse-common"
|
|
3
|
-
version = "2025.0.
|
|
3
|
+
version = "2025.0.6"
|
|
4
4
|
description = "Software framework to support hardware testing"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "IVS KU Leuven"}
|
|
@@ -36,10 +36,13 @@ dependencies = [
|
|
|
36
36
|
[project.entry-points."cgse.version"]
|
|
37
37
|
cgse-common = 'egse'
|
|
38
38
|
|
|
39
|
+
[project.entry-points."cgse.settings"]
|
|
40
|
+
cgse-common = "cgse_common:settings.yaml"
|
|
41
|
+
|
|
39
42
|
[tool.pytest.ini_options]
|
|
40
43
|
pythonpath = "src"
|
|
41
44
|
testpaths = ["tests"]
|
|
42
|
-
addopts = "-ra --cov --cov-report html"
|
|
45
|
+
addopts = "-ra --cov --cov-branch --cov-report html"
|
|
43
46
|
filterwarnings = [
|
|
44
47
|
"ignore::DeprecationWarning"
|
|
45
48
|
]
|
|
@@ -47,6 +50,7 @@ filterwarnings = [
|
|
|
47
50
|
[tool.coverage.run]
|
|
48
51
|
omit = [
|
|
49
52
|
"tests/*",
|
|
53
|
+
"conftest.py",
|
|
50
54
|
]
|
|
51
55
|
|
|
52
56
|
[tool.hatch.build.targets.sdist]
|
|
@@ -59,7 +63,7 @@ exclude = [
|
|
|
59
63
|
]
|
|
60
64
|
|
|
61
65
|
[tool.hatch.build.targets.wheel]
|
|
62
|
-
packages = ["src/egse"]
|
|
66
|
+
packages = ["src/egse", "src/cgse-common"]
|
|
63
67
|
|
|
64
68
|
[tool.ruff]
|
|
65
69
|
line-length = 120
|
|
File without changes
|
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
PACKAGES:
|
|
2
|
+
CGSE_COMMON: Common classes, functions, decorators, etc. for the CGSE
|
|
3
|
+
|
|
1
4
|
SITE:
|
|
2
|
-
ID:
|
|
5
|
+
ID: XXXX # The SITE ID shall be filled in by the local settings file
|
|
3
6
|
SSH_SERVER: localhost # The IP address of the SSH server on your site
|
|
4
7
|
SSH_PORT: 22 # The TCP/IP port on which the SSH server is listening
|
|
5
8
|
|
|
@@ -10,6 +10,8 @@ import warnings
|
|
|
10
10
|
from typing import Callable
|
|
11
11
|
from typing import Optional
|
|
12
12
|
|
|
13
|
+
import rich
|
|
14
|
+
|
|
13
15
|
from egse.settings import Settings
|
|
14
16
|
from egse.system import get_caller_info
|
|
15
17
|
|
|
@@ -227,7 +229,14 @@ def profile_func(output_file=None, sort_by='cumulative', lines_to_print=None, st
|
|
|
227
229
|
|
|
228
230
|
|
|
229
231
|
def profile(func):
|
|
230
|
-
"""
|
|
232
|
+
"""
|
|
233
|
+
Prints the function signature and return value to stdout.
|
|
234
|
+
|
|
235
|
+
This function checks the `Settings.profiling()` value and only prints out
|
|
236
|
+
profiling information if this returns True.
|
|
237
|
+
|
|
238
|
+
Profiling can be activated with `Settings.set_profiling(True)`.
|
|
239
|
+
"""
|
|
231
240
|
if not hasattr(profile, "counter"):
|
|
232
241
|
profile.counter = 0
|
|
233
242
|
|
|
@@ -240,10 +249,10 @@ def profile(func):
|
|
|
240
249
|
signature = ", ".join(args_repr + kwargs_repr)
|
|
241
250
|
caller = get_caller_info(level=2)
|
|
242
251
|
prefix = f"PROFILE[{profile.counter}]: "
|
|
243
|
-
|
|
244
|
-
|
|
252
|
+
rich.print(f"{prefix}Calling {func.__name__}({signature})")
|
|
253
|
+
rich.print(f"{prefix} from {caller.filename} at {caller.lineno}.")
|
|
245
254
|
value = func(*args, **kwargs)
|
|
246
|
-
|
|
255
|
+
rich.print(f"{prefix}{func.__name__!r} returned {value!r}")
|
|
247
256
|
profile.counter -= 1
|
|
248
257
|
else:
|
|
249
258
|
value = func(*args, **kwargs)
|
|
@@ -40,32 +40,38 @@ WARNING:
|
|
|
40
40
|
from __future__ import annotations
|
|
41
41
|
|
|
42
42
|
__all__ = [
|
|
43
|
-
"
|
|
44
|
-
"get_site_id",
|
|
45
|
-
"get_data_storage_location",
|
|
46
|
-
"set_data_storage_location",
|
|
47
|
-
"get_data_storage_location_env_name",
|
|
43
|
+
"env_var",
|
|
48
44
|
"get_conf_data_location",
|
|
49
|
-
"set_conf_data_location",
|
|
50
45
|
"get_conf_data_location_env_name",
|
|
51
46
|
"get_conf_repo_location",
|
|
52
|
-
"set_conf_repo_location",
|
|
53
47
|
"get_conf_repo_location_env_name",
|
|
48
|
+
"get_data_storage_location",
|
|
49
|
+
"get_data_storage_location_env_name",
|
|
50
|
+
"get_local_settings_path",
|
|
51
|
+
"get_local_settings_env_name",
|
|
54
52
|
"get_log_file_location",
|
|
55
|
-
"set_log_file_location",
|
|
56
53
|
"get_log_file_location_env_name",
|
|
57
|
-
"
|
|
54
|
+
"get_project_name",
|
|
55
|
+
"get_site_id",
|
|
56
|
+
"set_conf_data_location",
|
|
57
|
+
"set_conf_repo_location",
|
|
58
|
+
"set_data_storage_location",
|
|
58
59
|
"set_local_settings",
|
|
59
|
-
"
|
|
60
|
+
"set_log_file_location",
|
|
60
61
|
]
|
|
61
62
|
|
|
63
|
+
import contextlib
|
|
62
64
|
import os
|
|
63
65
|
import warnings
|
|
64
66
|
from pathlib import Path
|
|
65
67
|
|
|
66
68
|
from egse.system import all_logging_disabled
|
|
69
|
+
from egse.system import get_caller_info
|
|
67
70
|
from egse.system import ignore_m_warning
|
|
68
71
|
|
|
72
|
+
from rich.console import Console
|
|
73
|
+
console = Console(width=100)
|
|
74
|
+
|
|
69
75
|
# Every project shall have a PROJECT and a SITE_ID environment variable set. This variable will be used to
|
|
70
76
|
# create the other environment variables that are specific to the project.
|
|
71
77
|
|
|
@@ -123,11 +129,18 @@ class _Env:
|
|
|
123
129
|
self._env = {}
|
|
124
130
|
|
|
125
131
|
def set(self, key, value):
|
|
126
|
-
|
|
132
|
+
if value is None:
|
|
133
|
+
if key in self._env:
|
|
134
|
+
del self._env[key]
|
|
135
|
+
else:
|
|
136
|
+
self._env[key] = value
|
|
127
137
|
|
|
128
138
|
def get(self, key) -> str:
|
|
129
139
|
return self._env.get(key, NoValue())
|
|
130
140
|
|
|
141
|
+
def __rich__(self):
|
|
142
|
+
return self._env
|
|
143
|
+
|
|
131
144
|
|
|
132
145
|
_env = _Env()
|
|
133
146
|
|
|
@@ -159,28 +172,60 @@ def _check_no_value(var_name, value):
|
|
|
159
172
|
"""Raise a ValueError when the value for the variable is NoValue."""
|
|
160
173
|
if value == NoValue():
|
|
161
174
|
project = _env.get("PROJECT")
|
|
162
|
-
env_name = var_name if var_name
|
|
175
|
+
env_name = var_name if var_name in ("PROJECT", "SITE_ID") else f"{project}_{var_name}"
|
|
163
176
|
raise ValueError(
|
|
164
177
|
f"The environment variable {env_name} is not set. "
|
|
165
178
|
f"Please set the environment variable before proceeding."
|
|
166
179
|
)
|
|
167
180
|
|
|
168
181
|
|
|
182
|
+
def set_default_environment(
|
|
183
|
+
project: str,
|
|
184
|
+
site_id: str,
|
|
185
|
+
data_storage_location: str | Path,
|
|
186
|
+
conf_data_location: str | Path | None = None,
|
|
187
|
+
conf_repo_location: str | Path | None = None,
|
|
188
|
+
log_file_location: str | Path | None = None,
|
|
189
|
+
local_settings: str | Path | None = None,
|
|
190
|
+
):
|
|
191
|
+
set_project_name(project)
|
|
192
|
+
set_site_id(site_id)
|
|
193
|
+
set_data_storage_location(data_storage_location)
|
|
194
|
+
set_conf_data_location(conf_data_location)
|
|
195
|
+
set_conf_repo_location(conf_repo_location)
|
|
196
|
+
set_log_file_location(log_file_location)
|
|
197
|
+
set_local_settings(local_settings)
|
|
198
|
+
|
|
199
|
+
|
|
169
200
|
def get_project_name():
|
|
201
|
+
"""Get the PROJECT name. Return None when the PROJECT is not set."""
|
|
170
202
|
return _env.get("PROJECT") or None
|
|
171
203
|
|
|
172
204
|
|
|
205
|
+
def set_project_name(name: str):
|
|
206
|
+
"""Set the environment variable PROJECT and its internal representation."""
|
|
207
|
+
os.environ["PROJECT"] = name
|
|
208
|
+
_env.set("PROJECT", name)
|
|
209
|
+
|
|
210
|
+
|
|
173
211
|
def get_site_id():
|
|
212
|
+
"""Get the SITE_ID. Return None if the SITE_ID is not set."""
|
|
174
213
|
return _env.get("SITE_ID") or None
|
|
175
214
|
|
|
176
215
|
|
|
216
|
+
def set_site_id(name: str):
|
|
217
|
+
"""Set the environment variable SITE_ID and its internal representation."""
|
|
218
|
+
os.environ["SITE_ID"] = name
|
|
219
|
+
_env.set("SITE_ID", name)
|
|
220
|
+
|
|
221
|
+
|
|
177
222
|
def get_data_storage_location_env_name() -> str:
|
|
178
223
|
"""Returns the name of the environment variable for the project."""
|
|
179
224
|
project = _env.get("PROJECT")
|
|
180
225
|
return f"{project}_DATA_STORAGE_LOCATION"
|
|
181
226
|
|
|
182
227
|
|
|
183
|
-
def set_data_storage_location(location: str | Path):
|
|
228
|
+
def set_data_storage_location(location: str | Path | None):
|
|
184
229
|
"""
|
|
185
230
|
Sets the environment variable and the internal representation to the given value.
|
|
186
231
|
|
|
@@ -189,14 +234,19 @@ def set_data_storage_location(location: str | Path):
|
|
|
189
234
|
"""
|
|
190
235
|
env_name = get_data_storage_location_env_name()
|
|
191
236
|
|
|
192
|
-
|
|
237
|
+
if location is None:
|
|
238
|
+
if env_name in os.environ:
|
|
239
|
+
del os.environ[env_name]
|
|
240
|
+
_env.set("DATA_STORAGE_LOCATION", None)
|
|
241
|
+
return
|
|
242
|
+
|
|
193
243
|
if not Path(location).exists():
|
|
194
244
|
warnings.warn(
|
|
195
245
|
f"The location you provided for the environment variable {env_name} doesn't exist: {location}."
|
|
196
246
|
)
|
|
197
247
|
|
|
198
|
-
os.environ[env_name] = location
|
|
199
|
-
_env.set('DATA_STORAGE_LOCATION', location)
|
|
248
|
+
os.environ[env_name] = str(location)
|
|
249
|
+
_env.set('DATA_STORAGE_LOCATION', str(location))
|
|
200
250
|
|
|
201
251
|
|
|
202
252
|
def get_data_storage_location(site_id: str = None) -> str:
|
|
@@ -223,6 +273,9 @@ def get_data_storage_location(site_id: str = None) -> str:
|
|
|
223
273
|
"""
|
|
224
274
|
global _env
|
|
225
275
|
|
|
276
|
+
project = _env.get("PROJECT")
|
|
277
|
+
_check_no_value("PROJECT", project)
|
|
278
|
+
|
|
226
279
|
site_id = site_id or _env.get("SITE_ID")
|
|
227
280
|
_check_no_value("SITE_ID", site_id)
|
|
228
281
|
|
|
@@ -240,7 +293,7 @@ def get_conf_data_location_env_name() -> str:
|
|
|
240
293
|
return f"{project}_CONF_DATA_LOCATION"
|
|
241
294
|
|
|
242
295
|
|
|
243
|
-
def set_conf_data_location(location: str | Path):
|
|
296
|
+
def set_conf_data_location(location: str | Path | None):
|
|
244
297
|
"""
|
|
245
298
|
Sets the environment variable and the internal representation to the given value.
|
|
246
299
|
|
|
@@ -250,7 +303,12 @@ def set_conf_data_location(location: str | Path):
|
|
|
250
303
|
|
|
251
304
|
env_name = get_conf_data_location_env_name()
|
|
252
305
|
|
|
253
|
-
|
|
306
|
+
if location is None:
|
|
307
|
+
if env_name in os.environ:
|
|
308
|
+
del os.environ[env_name]
|
|
309
|
+
_env.set("CONF_DATA_LOCATION", None)
|
|
310
|
+
return
|
|
311
|
+
|
|
254
312
|
if not Path(location).exists():
|
|
255
313
|
warnings.warn(
|
|
256
314
|
f"The location you provided for the environment variable {env_name} doesn't exist: {location}."
|
|
@@ -303,7 +361,7 @@ def get_log_file_location_env_name():
|
|
|
303
361
|
return f"{project}_LOG_FILE_LOCATION"
|
|
304
362
|
|
|
305
363
|
|
|
306
|
-
def set_log_file_location(location: str | Path):
|
|
364
|
+
def set_log_file_location(location: str | Path | None):
|
|
307
365
|
"""
|
|
308
366
|
Sets the environment variable and the internal representation to the given value.
|
|
309
367
|
|
|
@@ -313,7 +371,12 @@ def set_log_file_location(location: str | Path):
|
|
|
313
371
|
|
|
314
372
|
env_name = get_log_file_location_env_name()
|
|
315
373
|
|
|
316
|
-
|
|
374
|
+
if location is None:
|
|
375
|
+
if env_name in os.environ:
|
|
376
|
+
del os.environ[env_name]
|
|
377
|
+
_env.set("LOG_FILE_LOCATION", None)
|
|
378
|
+
return
|
|
379
|
+
|
|
317
380
|
if not Path(location).exists():
|
|
318
381
|
warnings.warn(
|
|
319
382
|
f"The location you provided for the environment variable {env_name} doesn't exist: {location}."
|
|
@@ -365,17 +428,24 @@ def get_local_settings_env_name() -> str:
|
|
|
365
428
|
return f"{project}_LOCAL_SETTINGS"
|
|
366
429
|
|
|
367
430
|
|
|
368
|
-
def set_local_settings(path: str | Path):
|
|
431
|
+
def set_local_settings(path: str | Path | None):
|
|
369
432
|
"""
|
|
370
433
|
Sets the environment variable and the internal representation to the given value.
|
|
371
434
|
|
|
435
|
+
When the path is set to None, the environment variable will be unset.
|
|
436
|
+
|
|
372
437
|
Warnings:
|
|
373
438
|
Issues a warning when the given path doesn't exist.
|
|
374
439
|
"""
|
|
375
440
|
|
|
376
441
|
env_name = get_local_settings_env_name()
|
|
377
442
|
|
|
378
|
-
|
|
443
|
+
if path is None:
|
|
444
|
+
if env_name in os.environ:
|
|
445
|
+
del os.environ[env_name]
|
|
446
|
+
_env.set('LOCAL_SETTINGS', None)
|
|
447
|
+
return
|
|
448
|
+
|
|
379
449
|
if not Path(path).exists():
|
|
380
450
|
warnings.warn(
|
|
381
451
|
f"The location you provided for the environment variable {env_name} doesn't exist: {path}."
|
|
@@ -385,18 +455,35 @@ def set_local_settings(path: str | Path):
|
|
|
385
455
|
_env.set('LOCAL_SETTINGS', path)
|
|
386
456
|
|
|
387
457
|
|
|
388
|
-
def
|
|
389
|
-
"""
|
|
458
|
+
def get_local_settings_path() -> str or None:
|
|
459
|
+
"""
|
|
460
|
+
Returns the fully qualified filename of the local settings YAML file. When the local settings environment
|
|
461
|
+
variable is not defined or is an empty string, None is returned.
|
|
462
|
+
|
|
463
|
+
Warnings:
|
|
464
|
+
- When the local settings environment variable is not defined, or
|
|
465
|
+
- when the path defined by the environment variable doesn't exist.
|
|
466
|
+
"""
|
|
390
467
|
|
|
391
468
|
local_settings = _env.get("LOCAL_SETTINGS")
|
|
392
469
|
|
|
393
|
-
if
|
|
470
|
+
if not local_settings:
|
|
471
|
+
warnings.warn(f"The local settings environment variable '{get_local_settings_env_name()}' "
|
|
472
|
+
f"is not defined or is an empty string.")
|
|
473
|
+
return None
|
|
474
|
+
|
|
475
|
+
if not Path(local_settings).exists():
|
|
394
476
|
warnings.warn(
|
|
395
|
-
f"The local settings '{local_settings}' doesn't exist. As a result, "
|
|
477
|
+
f"The local settings path '{local_settings}' doesn't exist. As a result, "
|
|
396
478
|
f"the local settings for your project will not be loaded."
|
|
397
479
|
)
|
|
398
480
|
|
|
399
|
-
return local_settings
|
|
481
|
+
return local_settings
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def has_conf_repo_location() -> bool:
|
|
485
|
+
location = _env.get("CONF_REPO_LOCATION")
|
|
486
|
+
return True if location else False
|
|
400
487
|
|
|
401
488
|
|
|
402
489
|
def get_conf_repo_location_env_name() -> str:
|
|
@@ -405,28 +492,50 @@ def get_conf_repo_location_env_name() -> str:
|
|
|
405
492
|
return f"{project}_CONF_REPO_LOCATION"
|
|
406
493
|
|
|
407
494
|
|
|
408
|
-
def get_conf_repo_location() -> str:
|
|
409
|
-
"""
|
|
495
|
+
def get_conf_repo_location() -> str | None:
|
|
496
|
+
"""
|
|
497
|
+
Returns the fully qualified name of the location of the repository with
|
|
498
|
+
configuration and calibration data.
|
|
499
|
+
|
|
500
|
+
Returns None if no environment variable was defined or if the location doesn't exist.
|
|
501
|
+
In both cases a Warning is issued.
|
|
502
|
+
"""
|
|
410
503
|
|
|
411
504
|
location = _env.get("CONF_REPO_LOCATION")
|
|
412
505
|
|
|
413
|
-
if location
|
|
506
|
+
if location in (None, NoValue()):
|
|
507
|
+
warnings.warn(
|
|
508
|
+
f"The environment variable for the configuration data repository is "
|
|
509
|
+
f"not defined ({get_conf_repo_location_env_name()})."
|
|
510
|
+
)
|
|
511
|
+
return None
|
|
512
|
+
|
|
513
|
+
if not Path(location).exists():
|
|
414
514
|
warnings.warn(f"The location of the configuration data repository doesn't exist: {location}.")
|
|
515
|
+
return None
|
|
415
516
|
|
|
416
|
-
return location
|
|
517
|
+
return location
|
|
417
518
|
|
|
418
519
|
|
|
419
|
-
def set_conf_repo_location(location: str):
|
|
520
|
+
def set_conf_repo_location(location: str | Path | None):
|
|
420
521
|
"""
|
|
421
522
|
Sets the environment variable and the internal representation to the given value.
|
|
422
523
|
|
|
524
|
+
When the location is None, the environment variable will be unset and its internal
|
|
525
|
+
representation will be NoValue().
|
|
526
|
+
|
|
423
527
|
Warnings:
|
|
424
528
|
Issues a warning when the given location doesn't exist.
|
|
425
529
|
"""
|
|
426
530
|
|
|
427
531
|
env_name = get_conf_repo_location_env_name()
|
|
428
532
|
|
|
429
|
-
|
|
533
|
+
if location is None:
|
|
534
|
+
if env_name in os.environ:
|
|
535
|
+
del os.environ[env_name]
|
|
536
|
+
_env.set("CONF_REPO_LOCATION", None)
|
|
537
|
+
return
|
|
538
|
+
|
|
430
539
|
if not Path(location).exists():
|
|
431
540
|
warnings.warn(
|
|
432
541
|
f"The location you provided for the environment variable {env_name} doesn't exist: {location}."
|
|
@@ -436,7 +545,69 @@ def set_conf_repo_location(location: str):
|
|
|
436
545
|
_env.set('CONF_REPO_LOCATION', location)
|
|
437
546
|
|
|
438
547
|
|
|
439
|
-
|
|
548
|
+
def print_env():
|
|
549
|
+
"""
|
|
550
|
+
Prints out the mandatory and known environment variables at the time of the
|
|
551
|
+
function call. The function and lineno is also printed for information.
|
|
552
|
+
"""
|
|
553
|
+
col_width = 30
|
|
554
|
+
|
|
555
|
+
console = Console(width=200)
|
|
556
|
+
|
|
557
|
+
with warnings.catch_warnings():
|
|
558
|
+
warnings.simplefilter("ignore")
|
|
559
|
+
caller_info = get_caller_info(level=2)
|
|
560
|
+
console.print(f"[b]Environment as in {caller_info.filename}:{caller_info.lineno}[/]")
|
|
561
|
+
console.print(f" {'PROJECT':{col_width}s}: {get_project_name()}")
|
|
562
|
+
console.print(f" {'SITE_ID':{col_width}s}: {get_site_id()}")
|
|
563
|
+
console.print(f" {get_data_storage_location_env_name():{col_width}s}: {get_data_storage_location()}")
|
|
564
|
+
console.print(f" {get_log_file_location_env_name():{col_width}s}: {get_log_file_location()}")
|
|
565
|
+
console.print(f" {get_conf_data_location_env_name():{col_width}s}: {get_conf_data_location()}")
|
|
566
|
+
console.print(f" {get_conf_repo_location_env_name():{col_width}s}: {get_conf_repo_location()}")
|
|
567
|
+
console.print(f" {get_local_settings_env_name():{col_width}s}: {get_local_settings_path()}")
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
@contextlib.contextmanager
|
|
571
|
+
def env_var(**kwargs):
|
|
572
|
+
"""
|
|
573
|
+
Context manager to run some code that need alternate settings for environment variables.
|
|
574
|
+
This will automatically initialize the CGSE environment upon entry and re-initialize upon exit.
|
|
575
|
+
|
|
576
|
+
NOTE: This context manager is different from the one from `egse.system` because of the CGSE environment changes.
|
|
577
|
+
|
|
578
|
+
Args:
|
|
579
|
+
**kwargs: dictionary with environment variables that are needed
|
|
580
|
+
|
|
581
|
+
Examples:
|
|
582
|
+
|
|
583
|
+
>>> from egse.env import env_var
|
|
584
|
+
>>> with env_var(PLATO_DATA_STORAGE_LOCATION="/Users/rik/data"):
|
|
585
|
+
... # do stuff that needs these alternate setting
|
|
586
|
+
... pass
|
|
587
|
+
|
|
588
|
+
"""
|
|
589
|
+
saved_env = {}
|
|
590
|
+
|
|
591
|
+
for k, v in kwargs.items():
|
|
592
|
+
saved_env[k] = os.environ.get(k)
|
|
593
|
+
if v is None:
|
|
594
|
+
if k in os.environ:
|
|
595
|
+
del os.environ[k]
|
|
596
|
+
else:
|
|
597
|
+
os.environ[k] = v
|
|
598
|
+
|
|
599
|
+
initialize()
|
|
600
|
+
|
|
601
|
+
yield
|
|
602
|
+
|
|
603
|
+
for k, v in saved_env.items():
|
|
604
|
+
if v is None:
|
|
605
|
+
if k in os.environ:
|
|
606
|
+
del os.environ[k]
|
|
607
|
+
else:
|
|
608
|
+
os.environ[k] = v
|
|
609
|
+
|
|
610
|
+
initialize()
|
|
440
611
|
|
|
441
612
|
|
|
442
613
|
def main(args: list | None = None): # pragma: no cover
|
|
@@ -517,8 +688,10 @@ def main(args: list | None = None): # pragma: no cover
|
|
|
517
688
|
location = get_data_storage_location()
|
|
518
689
|
if not Path(location).exists():
|
|
519
690
|
if args.mkdir:
|
|
520
|
-
rich.print(f" [green]⟶ Creating data storage location: {location}[/]")
|
|
691
|
+
rich.print(f" [green]⟶ Creating data storage location: {location} (+ daily + obs)[/]")
|
|
521
692
|
Path(location).mkdir(parents=True)
|
|
693
|
+
(Path(location) / "daily").mkdir()
|
|
694
|
+
(Path(location) / "obs").mkdir()
|
|
522
695
|
else:
|
|
523
696
|
rich.print(" [red]⟶ ERROR: The data storage location doesn't exist![/]")
|
|
524
697
|
else:
|
|
@@ -540,6 +713,16 @@ def main(args: list | None = None): # pragma: no cover
|
|
|
540
713
|
except ValueError as exc:
|
|
541
714
|
rich.print(f" get_conf_data_location() = [red]{exc}[/]")
|
|
542
715
|
|
|
716
|
+
try:
|
|
717
|
+
rich.print(f" {get_conf_repo_location() = }", flush=True, end="")
|
|
718
|
+
location = get_conf_repo_location()
|
|
719
|
+
if location is None or not Path(location).exists():
|
|
720
|
+
rich.print(" [red]⟶ ERROR: The configuration repository location doesn't exist![/]")
|
|
721
|
+
else:
|
|
722
|
+
rich.print()
|
|
723
|
+
except ValueError as exc:
|
|
724
|
+
rich.print(f" get_conf_repo_location() = [red]{exc}[/]")
|
|
725
|
+
|
|
543
726
|
try:
|
|
544
727
|
rich.print(f" {get_log_file_location() = }", flush=True, end="")
|
|
545
728
|
location = get_log_file_location()
|
|
@@ -555,8 +738,8 @@ def main(args: list | None = None): # pragma: no cover
|
|
|
555
738
|
rich.print(f" get_log_file_location() = [red]{exc}[/]")
|
|
556
739
|
|
|
557
740
|
try:
|
|
558
|
-
rich.print(f" {
|
|
559
|
-
location =
|
|
741
|
+
rich.print(f" {get_local_settings_path() = }", flush=True, end="")
|
|
742
|
+
location = get_local_settings_path()
|
|
560
743
|
if location is None or not Path(location).exists():
|
|
561
744
|
rich.print(" [red]⟶ ERROR: The local settings file is not defined or doesn't exist![/]")
|
|
562
745
|
else:
|
|
@@ -623,6 +806,9 @@ def main(args: list | None = None): # pragma: no cover
|
|
|
623
806
|
# PLATO_COMMON_EGSE_PATH - YES
|
|
624
807
|
|
|
625
808
|
|
|
809
|
+
ignore_m_warning('egse.env')
|
|
810
|
+
|
|
811
|
+
|
|
626
812
|
if __name__ == "__main__":
|
|
627
813
|
import sys
|
|
628
814
|
main(sys.argv[1:])
|
|
@@ -1,34 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides function to load plugins and settings from entry-points.
|
|
3
|
+
"""
|
|
4
|
+
__all__ = [
|
|
5
|
+
"load_plugins",
|
|
6
|
+
"get_file_infos",
|
|
7
|
+
"entry_points",
|
|
8
|
+
]
|
|
1
9
|
import logging
|
|
2
10
|
import os
|
|
3
11
|
import sys
|
|
4
12
|
import textwrap
|
|
5
13
|
import traceback
|
|
14
|
+
from importlib.metadata import EntryPoint
|
|
15
|
+
from pathlib import Path
|
|
6
16
|
|
|
7
17
|
import click
|
|
8
18
|
import rich
|
|
9
19
|
|
|
10
|
-
|
|
20
|
+
_LOGGER = logging.getLogger(__name__)
|
|
11
21
|
|
|
12
22
|
|
|
13
|
-
def entry_points(name: str):
|
|
23
|
+
def entry_points(name: str) -> set[EntryPoint]:
|
|
24
|
+
"""
|
|
25
|
+
Returns a set with all entry-points for the given group name.
|
|
26
|
+
|
|
27
|
+
When the name is not known as an entry-point group, an empty set will be returned.
|
|
28
|
+
"""
|
|
29
|
+
|
|
14
30
|
import importlib.metadata
|
|
15
31
|
|
|
16
32
|
try:
|
|
17
33
|
x = importlib.metadata.entry_points()[name]
|
|
18
34
|
return {ep for ep in x} # use of set here to remove duplicates
|
|
19
35
|
except KeyError:
|
|
20
|
-
return
|
|
36
|
+
return set()
|
|
21
37
|
|
|
22
38
|
|
|
23
39
|
def load_plugins(entry_point: str) -> dict:
|
|
24
|
-
|
|
40
|
+
"""
|
|
41
|
+
Returns a dictionary with plugins loaded. The keys are the names of the entry-points,
|
|
42
|
+
the values are the loaded modules or objects.
|
|
43
|
+
"""
|
|
25
44
|
eps = {}
|
|
26
45
|
for ep in entry_points(entry_point):
|
|
27
46
|
try:
|
|
28
47
|
eps[ep.name] = ep.load()
|
|
29
48
|
except Exception as exc:
|
|
30
49
|
eps[ep.name] = None
|
|
31
|
-
|
|
50
|
+
_LOGGER.error(f"Couldn't load entry point: {exc}")
|
|
51
|
+
|
|
52
|
+
return eps
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_file_infos(entry_point: str) -> dict[str, tuple[Path, str]]:
|
|
56
|
+
"""
|
|
57
|
+
Returns a dictionary with location and filename of all the entries found for
|
|
58
|
+
the given entry-point name.
|
|
59
|
+
|
|
60
|
+
The entry-points are interpreted as follows: <name> = "<module>:<filename>" where
|
|
61
|
+
|
|
62
|
+
- <name> is the name of the entry-point given in the pyproject.toml file
|
|
63
|
+
- <module> is a valid module name that can be imported and from which the location can be determined.
|
|
64
|
+
- <filename> is the name of the target file, e.g. a YAML file
|
|
65
|
+
|
|
66
|
+
As an example, for the `cgse-common` settings, the following entry in the `pyproject.toml`:
|
|
67
|
+
|
|
68
|
+
[project.entry-points."cgse.settings"]
|
|
69
|
+
cgse-common = "cgse_common:settings.yaml"
|
|
70
|
+
|
|
71
|
+
Note that the module name for this entry point has an underscore instead of a dash.
|
|
72
|
+
|
|
73
|
+
Return:
|
|
74
|
+
A dictionary with the entry point name as the key and a tuple (location, filename) as the value.
|
|
75
|
+
"""
|
|
76
|
+
from egse.system import get_module_location
|
|
77
|
+
|
|
78
|
+
eps = dict()
|
|
79
|
+
|
|
80
|
+
for ep in entry_points(entry_point):
|
|
81
|
+
try:
|
|
82
|
+
path = get_module_location(ep.module)
|
|
83
|
+
|
|
84
|
+
if path is None:
|
|
85
|
+
_LOGGER.error(
|
|
86
|
+
f"The entry-point '{ep.name}' is ill defined. The module part doesn't exist or is a "
|
|
87
|
+
f"namespace. No settings are loaded for this entry-point."
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
eps[ep.name] = (path, ep.attr)
|
|
91
|
+
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
_LOGGER.error(f"The entry point '{ep.name}' is ill defined: {exc}")
|
|
32
94
|
|
|
33
95
|
return eps
|
|
34
96
|
|
|
@@ -77,7 +139,7 @@ class BrokenCommand(click.Command):
|
|
|
77
139
|
self.help = textwrap.dedent(
|
|
78
140
|
f"""\
|
|
79
141
|
Warning: entry point could not be loaded. Contact its author for help.
|
|
80
|
-
|
|
142
|
+
|
|
81
143
|
{traceback.format_exc()}
|
|
82
144
|
"""
|
|
83
145
|
)
|
|
@@ -20,7 +20,7 @@ from prometheus_client import Summary
|
|
|
20
20
|
from egse.command import Command
|
|
21
21
|
from egse.command import CommandExecution
|
|
22
22
|
from egse.control import ControlServer
|
|
23
|
-
from egse.
|
|
23
|
+
from egse.response import Failure
|
|
24
24
|
from egse.device import DeviceConnectionObserver
|
|
25
25
|
from egse.system import format_datetime
|
|
26
26
|
from egse.zmq_ser import bind_address
|