cgse-common 2025.0.4__py3-none-any.whl → 2025.0.6__py3-none-any.whl
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.dist-info → cgse_common-2025.0.6.dist-info}/METADATA +1 -1
- {cgse_common-2025.0.4.dist-info → cgse_common-2025.0.6.dist-info}/RECORD +15 -15
- cgse_common-2025.0.6.dist-info/entry_points.txt +5 -0
- egse/control.py +0 -1
- egse/decorators.py +13 -4
- egse/env.py +223 -37
- egse/plugin.py +68 -6
- egse/protocol.py +1 -1
- egse/response.py +2 -1
- egse/services.py +4 -1
- egse/settings.py +260 -193
- egse/settings.yaml +4 -6
- egse/setup.py +49 -26
- egse/system.py +23 -17
- cgse_common-2025.0.4.dist-info/entry_points.txt +0 -2
- {cgse_common-2025.0.4.dist-info → cgse_common-2025.0.6.dist-info}/WHEEL +0 -0
egse/setup.py
CHANGED
|
@@ -120,6 +120,7 @@ import logging
|
|
|
120
120
|
import os
|
|
121
121
|
import re
|
|
122
122
|
import textwrap
|
|
123
|
+
import warnings
|
|
123
124
|
from functools import lru_cache
|
|
124
125
|
from pathlib import Path
|
|
125
126
|
from typing import Any
|
|
@@ -130,11 +131,14 @@ import rich
|
|
|
130
131
|
import yaml
|
|
131
132
|
from rich.tree import Tree
|
|
132
133
|
|
|
134
|
+
from egse.env import get_conf_data_location
|
|
133
135
|
from egse.env import get_conf_repo_location
|
|
134
136
|
from egse.env import get_conf_repo_location_env_name
|
|
135
137
|
from egse.env import get_data_storage_location
|
|
138
|
+
from egse.env import has_conf_repo_location
|
|
139
|
+
from egse.env import print_env
|
|
136
140
|
from egse.response import Failure
|
|
137
|
-
from egse.
|
|
141
|
+
from egse.settings import read_configuration_file
|
|
138
142
|
from egse.system import format_datetime
|
|
139
143
|
from egse.system import sanity_check
|
|
140
144
|
from egse.system import walk_dict_tree
|
|
@@ -218,8 +222,8 @@ def _load_yaml(resource_name: str):
|
|
|
218
222
|
[in_dir, fn] = parts if len(parts) > 1 else [None, parts[0]]
|
|
219
223
|
conf_location = get_conf_data_location()
|
|
220
224
|
try:
|
|
221
|
-
yaml_location = Path(conf_location) / in_dir
|
|
222
|
-
content = NavigableDict(Settings.load(
|
|
225
|
+
yaml_location = Path(conf_location) / in_dir
|
|
226
|
+
content = NavigableDict(Settings.load(location=yaml_location, filename=fn, add_local_settings=False))
|
|
223
227
|
except (TypeError, SettingsError) as exc:
|
|
224
228
|
raise ValueError(
|
|
225
229
|
f"Couldn't load resource '{resource_name}' from default {conf_location=}") from exc
|
|
@@ -227,7 +231,11 @@ def _load_yaml(resource_name: str):
|
|
|
227
231
|
|
|
228
232
|
|
|
229
233
|
def _load_pandas(resource_name: str, separator: str):
|
|
230
|
-
"""
|
|
234
|
+
"""
|
|
235
|
+
Find and return the content of the given file as a pandas DataFrame object.
|
|
236
|
+
|
|
237
|
+
The file is loaded relative from the location of the configuration data
|
|
238
|
+
as defined by `get_conf_data_location()`.
|
|
231
239
|
|
|
232
240
|
Args:
|
|
233
241
|
- resource_name: Filename, preceded by "pandas//".
|
|
@@ -336,7 +344,7 @@ class NavigableDict(dict):
|
|
|
336
344
|
|
|
337
345
|
"""
|
|
338
346
|
|
|
339
|
-
def __init__(self, head: dict = None):
|
|
347
|
+
def __init__(self, head: dict = None, label: str = None):
|
|
340
348
|
"""
|
|
341
349
|
Args:
|
|
342
350
|
head (dict): the original dictionary
|
|
@@ -344,6 +352,7 @@ class NavigableDict(dict):
|
|
|
344
352
|
head = head or {}
|
|
345
353
|
super().__init__(head)
|
|
346
354
|
self.__dict__["_memoized"] = {}
|
|
355
|
+
self.__dict__["_label"] = label
|
|
347
356
|
|
|
348
357
|
# By agreement, we only want the keys to be set as attributes if all keys are strings.
|
|
349
358
|
# That way we enforce that always all keys are navigable, or none.
|
|
@@ -572,7 +581,7 @@ class NavigableDict(dict):
|
|
|
572
581
|
return msg
|
|
573
582
|
|
|
574
583
|
def __rich__(self) -> Tree:
|
|
575
|
-
tree = Tree("NavigableDict", guide_style="dim")
|
|
584
|
+
tree = Tree(self.__dict__["_label"] or "NavigableDict", guide_style="dim")
|
|
576
585
|
walk_dict_tree(self, tree, text_style="dark grey")
|
|
577
586
|
return tree
|
|
578
587
|
|
|
@@ -636,8 +645,8 @@ class Setup(NavigableDict):
|
|
|
636
645
|
"""The Setup class represents a version of the configuration of the test facility, the
|
|
637
646
|
test setup and the Camera Under Test (CUT)."""
|
|
638
647
|
|
|
639
|
-
def __init__(self, nav_dict: NavigableDict | dict = None):
|
|
640
|
-
super().__init__(nav_dict or {})
|
|
648
|
+
def __init__(self, nav_dict: NavigableDict | dict = None, label: str = None):
|
|
649
|
+
super().__init__(nav_dict or {}, label=label)
|
|
641
650
|
|
|
642
651
|
@staticmethod
|
|
643
652
|
def from_dict(my_dict):
|
|
@@ -651,7 +660,7 @@ class Setup(NavigableDict):
|
|
|
651
660
|
>>> assert setup["ID"] == setup.ID == "my-setup-001"
|
|
652
661
|
|
|
653
662
|
"""
|
|
654
|
-
return Setup(my_dict)
|
|
663
|
+
return Setup(my_dict, label="Setup")
|
|
655
664
|
|
|
656
665
|
@staticmethod
|
|
657
666
|
def from_yaml_string(yaml_content: str = None):
|
|
@@ -674,27 +683,36 @@ class Setup(NavigableDict):
|
|
|
674
683
|
if "Setup" in setup_dict:
|
|
675
684
|
setup_dict = setup_dict["Setup"]
|
|
676
685
|
|
|
677
|
-
return Setup(setup_dict)
|
|
686
|
+
return Setup(setup_dict, label="Setup")
|
|
678
687
|
|
|
679
688
|
@staticmethod
|
|
680
689
|
@lru_cache
|
|
681
|
-
def from_yaml_file(filename: Union[str, Path] = None):
|
|
690
|
+
def from_yaml_file(filename: Union[str, Path] = None, add_local_settings: bool = True):
|
|
682
691
|
"""Loads a Setup from the given YAML file.
|
|
683
692
|
|
|
684
693
|
Args:
|
|
685
694
|
filename (str): the path of the YAML file to be loaded
|
|
695
|
+
add_local_settings (bool): if local settings shall be loaded and override the settings from the YAML file.
|
|
686
696
|
|
|
687
697
|
Returns:
|
|
688
698
|
a Setup that was loaded from the given location.
|
|
689
699
|
"""
|
|
690
|
-
from egse.settings import Settings
|
|
691
700
|
|
|
692
701
|
if not filename:
|
|
693
702
|
raise ValueError("Invalid argument to function: No filename or None given.")
|
|
694
703
|
|
|
695
|
-
|
|
704
|
+
# MODULE_LOGGER.info(f"Loading {filename}...")
|
|
705
|
+
|
|
706
|
+
setup_dict = read_configuration_file(filename, force=True)
|
|
707
|
+
if setup_dict == {}:
|
|
708
|
+
warnings.warn(f"Empty Setup file: {filename!s}")
|
|
709
|
+
|
|
710
|
+
try:
|
|
711
|
+
setup_dict = setup_dict["Setup"]
|
|
712
|
+
except KeyError:
|
|
713
|
+
warnings.warn(f"Setup file doesn't have a 'Setup' group: {filename!s}")
|
|
696
714
|
|
|
697
|
-
setup = Setup(setup_dict)
|
|
715
|
+
setup = Setup(setup_dict, label="Setup")
|
|
698
716
|
setup.set_private_attribute("_filename", filename)
|
|
699
717
|
if setup_id := _parse_filename_for_setup_id(str(filename)):
|
|
700
718
|
setup.set_private_attribute("_setup_id", setup_id)
|
|
@@ -911,18 +929,15 @@ def get_setup(setup_id: int = None):
|
|
|
911
929
|
|
|
912
930
|
def _check_conditions_for_get_path_of_setup_file(site_id: str) -> Path:
|
|
913
931
|
"""
|
|
914
|
-
Check some pre-conditions that need to be met before we try to determine the
|
|
915
|
-
the requested Setup file.
|
|
932
|
+
Check some pre-conditions that need to be met before we try to determine the
|
|
933
|
+
file path for the requested Setup file.
|
|
916
934
|
|
|
917
935
|
The following checks are performed:
|
|
918
936
|
|
|
919
|
-
* if the environment variable '
|
|
920
|
-
|
|
937
|
+
* if the environment variable '{PROJECT}_CONF_REPO_LOCATION' is set
|
|
921
938
|
* if the directory specified in the env variable actually exists
|
|
922
|
-
|
|
923
939
|
* if the folder with the Setups exists for the given site_id
|
|
924
940
|
|
|
925
|
-
|
|
926
941
|
Args:
|
|
927
942
|
site_id (str): the name of the test house
|
|
928
943
|
|
|
@@ -939,9 +954,12 @@ def _check_conditions_for_get_path_of_setup_file(site_id: str) -> Path:
|
|
|
939
954
|
|
|
940
955
|
if not (repo_location := get_conf_repo_location()):
|
|
941
956
|
raise LookupError(
|
|
942
|
-
f"Environment variable doesn't exist
|
|
957
|
+
f"Environment variable doesn't exist or points to an invalid location, please (re-)define"
|
|
958
|
+
f" {repo_location_env} and try again."
|
|
943
959
|
)
|
|
944
960
|
|
|
961
|
+
print_env()
|
|
962
|
+
|
|
945
963
|
repo_location = Path(repo_location)
|
|
946
964
|
setup_location = repo_location / 'data' / site_id / 'conf'
|
|
947
965
|
|
|
@@ -962,11 +980,13 @@ def _check_conditions_for_get_path_of_setup_file(site_id: str) -> Path:
|
|
|
962
980
|
|
|
963
981
|
def get_path_of_setup_file(setup_id: int, site_id: str) -> Path:
|
|
964
982
|
"""
|
|
965
|
-
Returns the Path to the last Setup file for the given site_id. The last Setup
|
|
966
|
-
with the largest setup_id number.
|
|
983
|
+
Returns the Path to the last Setup file for the given site_id. The last Setup
|
|
984
|
+
file is the file with the largest setup_id number.
|
|
967
985
|
|
|
968
|
-
This function needs the environment variable <PROJECT>_CONF_REPO_LOCATION to
|
|
969
|
-
location of the repository with configuration data on your
|
|
986
|
+
This function needs the environment variable <PROJECT>_CONF_REPO_LOCATION to
|
|
987
|
+
be defined as the location of the repository with configuration data on your
|
|
988
|
+
disk. If the repo is not defined, the configuration data location will be used
|
|
989
|
+
instead.
|
|
970
990
|
|
|
971
991
|
Args:
|
|
972
992
|
setup_id (int): the identifier for the requested Setup
|
|
@@ -984,7 +1004,10 @@ def get_path_of_setup_file(setup_id: int, site_id: str) -> Path:
|
|
|
984
1004
|
|
|
985
1005
|
"""
|
|
986
1006
|
|
|
987
|
-
|
|
1007
|
+
if not has_conf_repo_location():
|
|
1008
|
+
setup_location = Path(get_conf_data_location(site_id))
|
|
1009
|
+
else:
|
|
1010
|
+
setup_location = _check_conditions_for_get_path_of_setup_file(site_id)
|
|
988
1011
|
|
|
989
1012
|
if setup_id:
|
|
990
1013
|
files = list(setup_location.glob(f'SETUP_{site_id}_{setup_id:05d}_*.yaml'))
|
egse/system.py
CHANGED
|
@@ -28,6 +28,7 @@ import socket
|
|
|
28
28
|
import subprocess # For executing a shell command
|
|
29
29
|
import sys
|
|
30
30
|
import time
|
|
31
|
+
import warnings
|
|
31
32
|
from collections import namedtuple
|
|
32
33
|
from contextlib import contextmanager
|
|
33
34
|
from pathlib import Path
|
|
@@ -512,6 +513,9 @@ class AttributeDict(dict):
|
|
|
512
513
|
return self.__class__.__name__ + f"({{{sub_msg}{', ...' if len(self) > count else ''}}})"
|
|
513
514
|
|
|
514
515
|
|
|
516
|
+
attrdict = AttributeDict
|
|
517
|
+
|
|
518
|
+
|
|
515
519
|
def walk_dict_tree(dictionary: dict, tree: Tree, text_style: str = "green"):
|
|
516
520
|
for k, v in dictionary.items():
|
|
517
521
|
if isinstance(v, dict):
|
|
@@ -931,22 +935,23 @@ def env_var(**kwargs):
|
|
|
931
935
|
|
|
932
936
|
"""
|
|
933
937
|
saved_env = {}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
938
|
+
|
|
939
|
+
for k, v in kwargs.items():
|
|
940
|
+
saved_env[k] = os.environ.get(k)
|
|
941
|
+
if v is None:
|
|
942
|
+
if k in os.environ:
|
|
943
|
+
del os.environ[k]
|
|
944
|
+
else:
|
|
945
|
+
os.environ[k] = v
|
|
946
|
+
|
|
947
|
+
yield
|
|
948
|
+
|
|
949
|
+
for k, v in saved_env.items():
|
|
950
|
+
if v is None:
|
|
951
|
+
if k in os.environ:
|
|
952
|
+
del os.environ[k]
|
|
953
|
+
else:
|
|
954
|
+
os.environ[k] = v
|
|
950
955
|
|
|
951
956
|
|
|
952
957
|
def filter_by_attr(elements: Iterable, **attrs) -> List:
|
|
@@ -1120,7 +1125,7 @@ def is_namespace(module) -> bool:
|
|
|
1120
1125
|
return False
|
|
1121
1126
|
|
|
1122
1127
|
|
|
1123
|
-
def get_package_location(module) -> List[Path]:
|
|
1128
|
+
def get_package_location(module: str) -> List[Path]:
|
|
1124
1129
|
"""
|
|
1125
1130
|
Retrieves the file system locations associated with a Python package.
|
|
1126
1131
|
|
|
@@ -1153,6 +1158,7 @@ def get_package_location(module) -> List[Path]:
|
|
|
1153
1158
|
try:
|
|
1154
1159
|
module = importlib.import_module(module)
|
|
1155
1160
|
except TypeError:
|
|
1161
|
+
warnings.warn(f"The module is not found or is not valid: {module_name}.")
|
|
1156
1162
|
return []
|
|
1157
1163
|
|
|
1158
1164
|
if is_namespace(module):
|
|
File without changes
|