cgse-common 2024.1.1__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-2024.1.1.dist-info/METADATA +64 -0
- cgse_common-2024.1.1.dist-info/RECORD +32 -0
- cgse_common-2024.1.1.dist-info/WHEEL +4 -0
- cgse_common-2024.1.1.dist-info/entry_points.txt +2 -0
- egse/bits.py +318 -0
- egse/command.py +699 -0
- egse/config.py +289 -0
- egse/control.py +429 -0
- egse/decorators.py +419 -0
- egse/device.py +269 -0
- egse/env.py +279 -0
- egse/exceptions.py +88 -0
- egse/mixin.py +464 -0
- egse/monitoring.py +96 -0
- egse/observer.py +41 -0
- egse/obsid.py +161 -0
- egse/persistence.py +58 -0
- egse/plugin.py +97 -0
- egse/process.py +460 -0
- egse/protocol.py +607 -0
- egse/proxy.py +522 -0
- egse/reload.py +122 -0
- egse/resource.py +438 -0
- egse/services.py +212 -0
- egse/services.yaml +51 -0
- egse/settings.py +379 -0
- egse/settings.yaml +981 -0
- egse/setup.py +1180 -0
- egse/state.py +173 -0
- egse/system.py +1499 -0
- egse/version.py +178 -0
- egse/zmq_ser.py +69 -0
egse/env.py
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functionality to work with and check your Python environment.
|
|
3
|
+
"""
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from egse.system import all_logging_disabled
|
|
7
|
+
from egse.system import ignore_m_warning
|
|
8
|
+
|
|
9
|
+
ENV_PLATO_COMMON_EGSE = "PLATO_COMMON_EGSE_PATH"
|
|
10
|
+
ENV_PLATO_INSTALL = "PLATO_INSTALL_LOCATION"
|
|
11
|
+
ENV_PLATO_CONF_DATA = "PLATO_CONF_DATA_LOCATION"
|
|
12
|
+
ENV_PLATO_CONF_REPO = "PLATO_CONF_REPO_LOCATION"
|
|
13
|
+
ENV_PLATO_STORAGE_DATA = "PLATO_DATA_STORAGE_LOCATION"
|
|
14
|
+
ENV_PLATO_LOG_DATA = "PLATO_LOG_FILE_LOCATION"
|
|
15
|
+
ENV_PLATO_LOCAL_SETTINGS = "PLATO_LOCAL_SETTINGS"
|
|
16
|
+
|
|
17
|
+
PLATO_ENV_VARIABLES = [globals()[x] for x in globals() if x.startswith('ENV_PLATO_')]
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"get_data_storage_location",
|
|
21
|
+
"get_conf_data_location",
|
|
22
|
+
"get_log_file_location",
|
|
23
|
+
*PLATO_ENV_VARIABLES
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_data_storage_location(setup=None, site_id: str = None) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Returns the full path of the data storage location for the Site as
|
|
30
|
+
in the given Setup. If the Setup is not given, it is requested from the
|
|
31
|
+
configuration manager unless the `site_id` argument is given.
|
|
32
|
+
|
|
33
|
+
Note: when you specify the `site_id` as an argument, it takes precedence
|
|
34
|
+
over the site_id that is specified in the Setup.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
setup: the Setup from which the Camera name and Site ID are taken
|
|
38
|
+
site_id: the site identifier (to be used instead of the site_id in the Setup)
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
The full path of data storage location as a string.
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
A ValueError when no Setup can be loaded.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
# FIXME: this should be made independent of PLATO, maybe use CGSE_STORAGE_LOCATION as environment variable.
|
|
48
|
+
|
|
49
|
+
# FIXME: use CGSE_SITE_ID if Setup can not be determined.
|
|
50
|
+
|
|
51
|
+
import os
|
|
52
|
+
|
|
53
|
+
if site_id is None:
|
|
54
|
+
|
|
55
|
+
from egse.setup import Setup
|
|
56
|
+
from egse.state import GlobalState
|
|
57
|
+
setup: Setup = setup or GlobalState.setup
|
|
58
|
+
|
|
59
|
+
if setup is None:
|
|
60
|
+
raise ValueError(
|
|
61
|
+
"Could not determine Setup, which is None, even after loading from the configuration manager."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
site = setup.site_id
|
|
65
|
+
else:
|
|
66
|
+
site = site_id
|
|
67
|
+
|
|
68
|
+
data_root = os.environ[ENV_PLATO_STORAGE_DATA]
|
|
69
|
+
data_root = data_root.rstrip('/')
|
|
70
|
+
|
|
71
|
+
return data_root if data_root.endswith(site) else f"{data_root}/{site}"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_conf_data_location(setup=None) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Returns the full path of the location of the Setups for the Site.
|
|
77
|
+
If the Setup is not given, it is requested from the configuration manager.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
setup: the Setup from which the Camera name and Site ID are taken
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The full path of location of the Setups as a string.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
A ValueError when no Setup can be loaded.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
data_root = get_data_storage_location(setup=setup)
|
|
90
|
+
|
|
91
|
+
return f"{data_root}/conf"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def get_log_file_location() -> str:
|
|
95
|
+
"""
|
|
96
|
+
Returns the full path of the location of the log files. The log file location is read from the environment
|
|
97
|
+
variable PLATO_LOG_FILE_LOCATION. The location shall be independent of the Setup, Camera ID or any other
|
|
98
|
+
setting that is subject to change.
|
|
99
|
+
|
|
100
|
+
If the environment variable is not set, a default log file location is created from the data storage location as
|
|
101
|
+
follows: $PLATO_DATA_STORAGE_LOCATION/<SITE_ID>/log.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
The full path of location of the log files as a string.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
# FIXME: this should be made independent of PLATO, maybe put the log file in the cwd unless an environment
|
|
108
|
+
# variable CGSE_LOG_FILE_LOCATION is defined and the location exists and is writable.
|
|
109
|
+
|
|
110
|
+
import os
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
log_data_root = os.environ[ENV_PLATO_LOG_DATA]
|
|
114
|
+
except KeyError:
|
|
115
|
+
data_root = os.environ[ENV_PLATO_STORAGE_DATA]
|
|
116
|
+
data_root = data_root.rstrip('/')
|
|
117
|
+
|
|
118
|
+
from egse.settings import get_site_id
|
|
119
|
+
site = get_site_id()
|
|
120
|
+
|
|
121
|
+
log_data_root = f"{data_root}/{site}/log"
|
|
122
|
+
|
|
123
|
+
return log_data_root
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
ignore_m_warning('egse.env')
|
|
127
|
+
|
|
128
|
+
if __name__ == "__main__":
|
|
129
|
+
|
|
130
|
+
import argparse
|
|
131
|
+
import os
|
|
132
|
+
import sys
|
|
133
|
+
import rich
|
|
134
|
+
|
|
135
|
+
from egse.config import get_common_egse_root
|
|
136
|
+
|
|
137
|
+
parser = argparse.ArgumentParser()
|
|
138
|
+
parser.add_argument(
|
|
139
|
+
"--full",
|
|
140
|
+
default=False,
|
|
141
|
+
action="store_true",
|
|
142
|
+
help="Print a full report on environment variables and paths.",
|
|
143
|
+
)
|
|
144
|
+
parser.add_argument(
|
|
145
|
+
"--doc",
|
|
146
|
+
default=False,
|
|
147
|
+
action="store_true",
|
|
148
|
+
help="Print help on the environment variables and paths.",
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
args = parser.parse_args()
|
|
152
|
+
|
|
153
|
+
def check_env_dir(env_var: str):
|
|
154
|
+
|
|
155
|
+
value = os.environ.get(env_var)
|
|
156
|
+
|
|
157
|
+
if value is None:
|
|
158
|
+
value = "[bold red]not set"
|
|
159
|
+
elif not value.startswith('/'):
|
|
160
|
+
value = f"[default]{value} [bold orange3](this is a relative path!)"
|
|
161
|
+
elif not os.path.exists(value):
|
|
162
|
+
value = f"[default]{value} [bold red](location doesn't exist!)"
|
|
163
|
+
elif not os.path.isdir(value):
|
|
164
|
+
value = f"[default]{value} [bold red](location is not a directory!)"
|
|
165
|
+
else:
|
|
166
|
+
value = f"[default]{value}"
|
|
167
|
+
return value
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def check_env_file(env_var: str):
|
|
171
|
+
|
|
172
|
+
value = os.environ.get(env_var)
|
|
173
|
+
|
|
174
|
+
if value is None:
|
|
175
|
+
value = "[bold red]not set"
|
|
176
|
+
elif not os.path.exists(value):
|
|
177
|
+
value = f"[default]{value} [bold red](location doesn't exist!)"
|
|
178
|
+
else:
|
|
179
|
+
value = f"[default]{value}"
|
|
180
|
+
return value
|
|
181
|
+
|
|
182
|
+
rich.print("Environment variables:")
|
|
183
|
+
|
|
184
|
+
for var in PLATO_ENV_VARIABLES:
|
|
185
|
+
if var.endswith("_SETTINGS"):
|
|
186
|
+
rich.print(f" {var} = {check_env_file(var)}")
|
|
187
|
+
else:
|
|
188
|
+
rich.print(f" {var} = {check_env_dir(var)}")
|
|
189
|
+
|
|
190
|
+
rich.print()
|
|
191
|
+
rich.print("Generated locations and filenames")
|
|
192
|
+
|
|
193
|
+
with all_logging_disabled():
|
|
194
|
+
try:
|
|
195
|
+
rich.print(f" {get_data_storage_location() = }", flush=True)
|
|
196
|
+
location = get_data_storage_location()
|
|
197
|
+
if not Path(location).exists():
|
|
198
|
+
rich.print("[red]ERROR: The generated data storage location doesn't exist![/]")
|
|
199
|
+
except ValueError as exc:
|
|
200
|
+
rich.print(f" get_data_storage_location() = [red]{exc}[/]")
|
|
201
|
+
|
|
202
|
+
try:
|
|
203
|
+
rich.print(f" {get_conf_data_location() = }", flush=True)
|
|
204
|
+
location = get_conf_data_location()
|
|
205
|
+
if not Path(location).exists():
|
|
206
|
+
rich.print("[red]ERROR: The generated configuration data location doesn't exist![/]")
|
|
207
|
+
except ValueError as exc:
|
|
208
|
+
rich.print(f" get_conf_data_location() = [red]{exc}[/]")
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
rich.print(f" {get_log_file_location() = }", flush=True)
|
|
212
|
+
location = get_log_file_location()
|
|
213
|
+
if not Path(location).exists():
|
|
214
|
+
rich.print("[red]ERROR: The generated log files location doesn't exist![/]")
|
|
215
|
+
except ValueError as exc:
|
|
216
|
+
rich.print(f" get_log_file_location() = [red]{exc}[/]")
|
|
217
|
+
|
|
218
|
+
if args.full:
|
|
219
|
+
rich.print()
|
|
220
|
+
rich.print(f" PYTHONPATH=[default]{os.environ.get('PYTHONPATH')}")
|
|
221
|
+
rich.print(f" PYTHONSTARTUP=[default]{os.environ.get('PYTHONSTARTUP')}")
|
|
222
|
+
rich.print()
|
|
223
|
+
python_path_msg = "\n ".join(sys.path)
|
|
224
|
+
rich.print(f" sys.path=[\n {python_path_msg}\n ]")
|
|
225
|
+
path_msg = "\n ".join(os.environ.get("PATH").split(":"))
|
|
226
|
+
rich.print(f" PATH=[\n {path_msg}\n ]")
|
|
227
|
+
|
|
228
|
+
help_msg = f"""
|
|
229
|
+
[bold]{ENV_PLATO_COMMON_EGSE}[/bold]:
|
|
230
|
+
This variable should point to the root of the working copy of the 'plato-common-egse'
|
|
231
|
+
project. Its value is usually '~/git/plato-common-egse' which is considered the default
|
|
232
|
+
location.
|
|
233
|
+
|
|
234
|
+
[bold]{ENV_PLATO_INSTALL}[/bold]:
|
|
235
|
+
This variable shall point to the location where the CGSE will be installed and is
|
|
236
|
+
usually set to `/cgse`. The variable is used by the [blue]update_cgse[/blue] script.
|
|
237
|
+
|
|
238
|
+
[bold]{ENV_PLATO_CONF_DATA}[/bold]:
|
|
239
|
+
This directory is the root folder for all the Setups of the site, the site is part
|
|
240
|
+
of the name. By default, this directory is located in the overall data storage folder.
|
|
241
|
+
|
|
242
|
+
[bold]{ENV_PLATO_CONF_REPO}[/bold]:
|
|
243
|
+
This variable is the root of the working copy of the 'plato-cgse-conf' project.
|
|
244
|
+
The value is usually set to `~/git/plato-cgse-conf`.
|
|
245
|
+
|
|
246
|
+
[bold]{ENV_PLATO_STORAGE_DATA}[/bold]:
|
|
247
|
+
This directory contains all the data files from the control servers and other
|
|
248
|
+
components. This folder is the root folder for all data from all cameras and
|
|
249
|
+
all sites. Below this folder shall be a folder for each of the cameras and in
|
|
250
|
+
there a sub-folder for each of the sites where that camera was tested. The
|
|
251
|
+
hierarchy is therefore: `$PLATO_DATA_STORAGE_LOCATION/<camera name>/<site id>.
|
|
252
|
+
Each of those folder shall contain at least the sub-folder [blue]daily[/blue], and [blue]obs[/blue].
|
|
253
|
+
|
|
254
|
+
There is also a file called [blue]obsid-table-<site id>.txt[/blue] which is maintained by
|
|
255
|
+
the configuration manager and contains information about the observations that
|
|
256
|
+
were run and the commands to start those observation.
|
|
257
|
+
|
|
258
|
+
[bold]{ENV_PLATO_LOG_DATA}[/bold]:
|
|
259
|
+
This directory contains the log files with all messages that were sent to the
|
|
260
|
+
logger control server. The log files are rotated on a daily basis at midnight UTC.
|
|
261
|
+
By default, this directory is also located in the overall data storage folder.
|
|
262
|
+
|
|
263
|
+
[bold]{ENV_PLATO_LOCAL_SETTINGS}[/bold]:
|
|
264
|
+
This file is used for local site-specific settings. When the environment
|
|
265
|
+
variable is not set, no local settings will be loaded. By default, this variable
|
|
266
|
+
is assumed to be '/cgse/local_settings.yaml'.
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
if args.doc:
|
|
270
|
+
rich.print(help_msg)
|
|
271
|
+
|
|
272
|
+
if not args.full:
|
|
273
|
+
rich.print()
|
|
274
|
+
rich.print("use the '--full' flag to get a more detailed report, '--doc' for help on the variables.")
|
|
275
|
+
|
|
276
|
+
# Do we still use these environment variables?
|
|
277
|
+
#
|
|
278
|
+
# PLATO_WORKDIR
|
|
279
|
+
# PLATO_COMMON_EGSE_PATH - YES
|
egse/exceptions.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
The Exception Hierarchy:
|
|
3
|
+
|
|
4
|
+
Exception
|
|
5
|
+
+-- CommonEGSEException
|
|
6
|
+
+-- Warning
|
|
7
|
+
+-- Error
|
|
8
|
+
+-- InvalidOperationError
|
|
9
|
+
+-- DeviceNotFoundError (should move to subclass of DeviceError)
|
|
10
|
+
+-- InternalStateError
|
|
11
|
+
+-- DeviceError
|
|
12
|
+
+-- DeviceControllerError
|
|
13
|
+
+-- DeviceConnectionError
|
|
14
|
+
+-- DeviceTimeoutError
|
|
15
|
+
+-- DeviceInterfaceError
|
|
16
|
+
+-- Failure
|
|
17
|
+
+-- HexapodError
|
|
18
|
+
+-- PMACError
|
|
19
|
+
+-- OGSEError
|
|
20
|
+
+-- ESLError
|
|
21
|
+
+-- FilterWheelError
|
|
22
|
+
+-- FilterWheel8smc4Error
|
|
23
|
+
+-- ShutterKSC1010Error
|
|
24
|
+
+-- WindowSizeError
|
|
25
|
+
+-- SettingsError
|
|
26
|
+
+-- StagesError
|
|
27
|
+
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CommonEGSEException(Exception):
|
|
32
|
+
"""The base exception for all errors and warnings in the Common-EGSE."""
|
|
33
|
+
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Error(CommonEGSEException):
|
|
38
|
+
"""The base class for all Common-EGSE Errors."""
|
|
39
|
+
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class Warning(CommonEGSEException):
|
|
44
|
+
"""The base class for all Common-EGSE Warnings."""
|
|
45
|
+
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FileIsEmptyError(Error):
|
|
50
|
+
"""Raised when a file is empty and that is unexpected."""
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class InvalidOperationError(Error):
|
|
55
|
+
"""
|
|
56
|
+
Raised when a certain operation is not valid in the given state,
|
|
57
|
+
circumstances or environment.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class InvalidInputError(Error):
|
|
64
|
+
""" Exception raised when the input is invalid after editing."""
|
|
65
|
+
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class DeviceNotFoundError(Error):
|
|
70
|
+
"""Raised when a device could not be located, or loaded."""
|
|
71
|
+
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class InternalStateError(Error):
|
|
76
|
+
"""Raised when an object encounters an internal state inconsistency."""
|
|
77
|
+
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class InternalError(Error):
|
|
82
|
+
"""Raised when an internal inconsistency occurred in a function, method or class."""
|
|
83
|
+
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class Abort(RuntimeError):
|
|
88
|
+
"""Internal Exception to signal a process to abort."""
|