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/state.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import logging
|
|
3
|
+
import textwrap
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from egse.decorators import borg
|
|
8
|
+
from egse.decorators import deprecate
|
|
9
|
+
from egse.setup import Setup
|
|
10
|
+
|
|
11
|
+
LOGGER = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class StateError(Exception):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class UnknownStateError(StateError):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class IllegalStateTransition(StateError):
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NotImplementedTransition(StateError):
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ConnectionStateInterface(abc.ABC):
|
|
31
|
+
"""
|
|
32
|
+
A class used to enforce the implementation of the _connection_ interface
|
|
33
|
+
to model the state of a (network) connection.
|
|
34
|
+
|
|
35
|
+
Subclasses only need to implement those methods that are applicable to
|
|
36
|
+
their state.
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# This class is to enforce the implementation of the interface on both the
|
|
41
|
+
# model, i.e. the Proxy, and the State class. At the same time, it will allow
|
|
42
|
+
# the State subclasses to implement only those methods that are applicable
|
|
43
|
+
# in their state.
|
|
44
|
+
|
|
45
|
+
@abc.abstractmethod
|
|
46
|
+
def connect(self, proxy):
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
@abc.abstractmethod
|
|
50
|
+
def disconnect(self, proxy):
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
@abc.abstractmethod
|
|
54
|
+
def reconnect(self, proxy):
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@borg
|
|
59
|
+
class _GlobalState:
|
|
60
|
+
"""
|
|
61
|
+
This class implements global state that is shared between instances of this class.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
# TODO (rik): turn command sequence into a class and move add_, clear_ and get_ to that class
|
|
65
|
+
|
|
66
|
+
def __init__(self):
|
|
67
|
+
self._dry_run = False
|
|
68
|
+
self._command_sequence = []
|
|
69
|
+
self._setup: Optional[Setup] = None
|
|
70
|
+
|
|
71
|
+
def __call__(self, *args, **kwargs):
|
|
72
|
+
return self
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def dry_run(self):
|
|
76
|
+
return self._dry_run
|
|
77
|
+
|
|
78
|
+
@dry_run.setter
|
|
79
|
+
def dry_run(self, flag: bool):
|
|
80
|
+
self._dry_run = flag
|
|
81
|
+
|
|
82
|
+
def add_command(self, cmd):
|
|
83
|
+
self._command_sequence.append(cmd)
|
|
84
|
+
|
|
85
|
+
def get_command_sequence(self):
|
|
86
|
+
return self._command_sequence
|
|
87
|
+
|
|
88
|
+
def clear_command_sequence(self):
|
|
89
|
+
self._command_sequence.clear()
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def setup(self) -> Optional[Setup]:
|
|
93
|
+
"""
|
|
94
|
+
Returns the currently active Setup from the configuration manager. Please note that each call
|
|
95
|
+
to this property sends a request to the configuration manager to return its current Setup. If
|
|
96
|
+
you are accessing information from the Setup in a loop or function that is called often, save
|
|
97
|
+
the Setup into a local variable before proceeding.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The currently active Setup or None (when the configuration manager is not reachable).
|
|
101
|
+
"""
|
|
102
|
+
return self.load_setup()
|
|
103
|
+
|
|
104
|
+
# This function should be the standard function to reload a setup from the configuration manager
|
|
105
|
+
# Since we have no proper CM yet, the function loads from the default setup.yaml file.
|
|
106
|
+
# But what happens then in other parts of the system, where e.g. the PM has also the 'rights'
|
|
107
|
+
# to call load_setup() on the CM_CS?
|
|
108
|
+
|
|
109
|
+
def load_setup(self) -> Optional[Setup]:
|
|
110
|
+
"""
|
|
111
|
+
Loads the currently active Setup from the Configuration manager. The current Setup is the Setup
|
|
112
|
+
that is defined and loaded in the Configuration manager. When the configuration manager is not
|
|
113
|
+
reachable, None will be returned and a warning will be logged.
|
|
114
|
+
|
|
115
|
+
Since the GlobalState should reflect the configuration of the test, it can only load the current
|
|
116
|
+
Setup from the configuration manager. If you need to work with different Setups, work with the `Setup`
|
|
117
|
+
class and the Configuration Manager directly.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
The currently active Setup or None.
|
|
121
|
+
"""
|
|
122
|
+
from egse.confman import ConfigurationManagerProxy
|
|
123
|
+
from egse.confman import is_configuration_manager_active
|
|
124
|
+
|
|
125
|
+
if is_configuration_manager_active():
|
|
126
|
+
with ConfigurationManagerProxy() as cm_proxy:
|
|
127
|
+
self._setup = cm_proxy.get_setup()
|
|
128
|
+
else:
|
|
129
|
+
LOGGER.warning(textwrap.dedent(
|
|
130
|
+
f"""\
|
|
131
|
+
Could not reach the Configuration Manager to request the Setup, returning the current local Setup.
|
|
132
|
+
|
|
133
|
+
Check if the Configuration Manager is running and why it can not be consulted. When it's
|
|
134
|
+
back on-line, do a 'load_setup()'.
|
|
135
|
+
"""
|
|
136
|
+
))
|
|
137
|
+
|
|
138
|
+
return self._setup
|
|
139
|
+
|
|
140
|
+
# FIXME:
|
|
141
|
+
# These two 'private' methods are still called in plato-test-scripts, so until that is fixed,
|
|
142
|
+
# leave the methods here
|
|
143
|
+
|
|
144
|
+
@deprecate(reason="this is a private function", alternative="reload_setup()")
|
|
145
|
+
def _reload_setup(self):
|
|
146
|
+
self._setup = Setup.from_yaml_file()
|
|
147
|
+
return self._setup
|
|
148
|
+
|
|
149
|
+
@deprecate(reason="this is a private function", alternative="reload_setup_from()")
|
|
150
|
+
def _reload_setup_from(self, filename: Path):
|
|
151
|
+
"""Used by the unit tests to load a predefined setup."""
|
|
152
|
+
self._setup = Setup.from_yaml_file(filename=filename)
|
|
153
|
+
return self.setup
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
GlobalState = _GlobalState()
|
|
157
|
+
|
|
158
|
+
__all__ = [
|
|
159
|
+
"GlobalState",
|
|
160
|
+
]
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
|
|
164
|
+
from rich import print
|
|
165
|
+
|
|
166
|
+
print(textwrap.dedent(
|
|
167
|
+
f"""\
|
|
168
|
+
GlobalState info:
|
|
169
|
+
Setup loaded: {GlobalState.setup.get_id()}
|
|
170
|
+
Dry run: {'ON' if GlobalState.dry_run else 'OFF'}
|
|
171
|
+
Command Sequence: {GlobalState.get_command_sequence()} \
|
|
172
|
+
""")
|
|
173
|
+
)
|