cgse-common 0.17.1__py3-none-any.whl → 0.17.3__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-0.17.1.dist-info → cgse_common-0.17.3.dist-info}/METADATA +1 -1
- {cgse_common-0.17.1.dist-info → cgse_common-0.17.3.dist-info}/RECORD +14 -18
- {cgse_common-0.17.1.dist-info → cgse_common-0.17.3.dist-info}/WHEEL +1 -1
- egse/bits.py +14 -17
- egse/decorators.py +6 -3
- egse/device.py +0 -70
- egse/env.py +2 -1
- egse/exceptions.py +3 -0
- egse/log.py +7 -8
- egse/scpi.py +47 -112
- egse/settings.py +31 -0
- egse/system.py +63 -24
- egse/version.py +24 -13
- egse/plugins/metrics/duckdb.py +0 -442
- egse/plugins/metrics/timescaledb.py +0 -596
- egse/ratelimit.py +0 -275
- egse/socketdevice.py +0 -379
- {cgse_common-0.17.1.dist-info → cgse_common-0.17.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
cgse_common/__init__.py,sha256=wTYOpVomEeDFFuqt4Ss9ROSAIa48UUnYCSafdEOx-CU,129
|
|
2
2
|
cgse_common/cgse.py,sha256=S8MxwJcSzqYNR0wirEscQw5CTg89AKORa8-NHRdrxJM,6642
|
|
3
3
|
cgse_common/settings.yaml,sha256=PS8HOoxbhwVoQ7zzDtZyhx25RZB6SGq3uXNuJTgtRIw,443
|
|
4
|
-
egse/bits.py,sha256=
|
|
4
|
+
egse/bits.py,sha256=6UrQdZ8nZ347rDdJ47a1PTWcq3fZt-c3siDjFfBGgiA,12389
|
|
5
5
|
egse/calibration.py,sha256=a5JDaXTC6fMwQ1M-qrwNO31Ass-yYSXxDQUK_PPsZg4,8818
|
|
6
6
|
egse/config.py,sha256=M821_d1IfNT17J3tt_TDjh4bGJgGiYviGBYR0I5v5LA,9639
|
|
7
7
|
egse/counter.py,sha256=7UwBeTAu213xdNdGAOYpUWNQ4jD4yVM1bOG10Ax4UFs,5097
|
|
8
|
-
egse/decorators.py,sha256=
|
|
9
|
-
egse/device.py,sha256=
|
|
8
|
+
egse/decorators.py,sha256=ZJgXKP8IEniOFd8nHljNeUNpQLAB2Z9q4UiQsnLFzhA,27204
|
|
9
|
+
egse/device.py,sha256=gfv5Eazf1nZt3U59w9RwSWnKnAMs4hZrhb4Zv5xBvGE,11431
|
|
10
10
|
egse/dicts.py,sha256=dUAq7PTPvs73OrZb2Fh3loxvYv4ifUiK6bBcgrFU77Y,3972
|
|
11
|
-
egse/env.py,sha256=
|
|
12
|
-
egse/exceptions.py,sha256=
|
|
11
|
+
egse/env.py,sha256=MWftGEmodckKbjXxFGm3WsQRnZ96wCDR3bci0KzZP0Y,31705
|
|
12
|
+
egse/exceptions.py,sha256=yhOtO5NkCxgvTyVo8fgTyxauX-ZtiEkxDB76ZdCbPrM,1301
|
|
13
13
|
egse/heartbeat.py,sha256=2SeZzX3tWFog1rgYThX-iaZPwHYq8TVma2ll7r624Eg,3039
|
|
14
14
|
egse/hk.py,sha256=AumSpB8SYXes75CB2iiKXfLkMK5IkVDHITFKrf8IT6g,32010
|
|
15
|
-
egse/log.py,sha256=
|
|
15
|
+
egse/log.py,sha256=5sdVQC2DfBlHbOQzY8ChzLjoL7kNDMErTZFaj97aNBE,5350
|
|
16
16
|
egse/metrics.py,sha256=2hHtJXG0Rn782l2bfmLNBbw6ucC5nf7jPnNzqbhP_Zs,7012
|
|
17
17
|
egse/observer.py,sha256=xQ7F7NVHqdRZ6IIsBM5M0kMuullMghoR98dwAsjgh0s,1287
|
|
18
18
|
egse/obsid.py,sha256=y87AYX5mtNEBqEtpEFEec2MhEmo1Hej3Wwi5od84wR8,5848
|
|
@@ -21,25 +21,21 @@ egse/plugin.py,sha256=RDH1R65vuxpEOSmibYoRPhtPsDLn7MIRXQkDhFgt3Hk,10337
|
|
|
21
21
|
egse/process.py,sha256=iw17U1c3nzTON7JQaHGZTN8KzqV-3WtbdX2GGUeevn4,26850
|
|
22
22
|
egse/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
egse/randomwalk.py,sha256=dllGv_F4AFYanp_A5ynBsAjglYzxaPYpRCBifwQScx4,6451
|
|
24
|
-
egse/ratelimit.py,sha256=JdJxD6UIi9LYngKEsG9zh8bTE9r_56D4EZCnp_fkrI0,9161
|
|
25
24
|
egse/reload.py,sha256=PzOE0m1tmcNcQPVFH8orMe_cMoQIIiH9Gw2anpQTC40,4717
|
|
26
25
|
egse/resource.py,sha256=kzNI6kJOE6Jd5QKJs2MkVAycUpwpOTLi1qydh3NSRng,15345
|
|
27
26
|
egse/response.py,sha256=F04uqOYv1ClpHgDLYZlKTuOCSldHs5TezI_4x6zf2Fw,2717
|
|
28
|
-
egse/scpi.py,sha256=
|
|
29
|
-
egse/settings.py,sha256=
|
|
27
|
+
egse/scpi.py,sha256=DBTvB_p7yaGVW1aNJ6yhxGhWCuSe2uFzMCjFOy3XmZM,13375
|
|
28
|
+
egse/settings.py,sha256=eiZ9eGydgF9lNBjHH8VqOgcFDxSdhO6dLs7pYA725lo,16849
|
|
30
29
|
egse/settings.yaml,sha256=mz9O2QqmiptezsMvxJRLhnC1ROwIHENX0nbnhMaXUpE,190
|
|
31
30
|
egse/setup.py,sha256=ezPYA3n1P3navdPR3qDxh0qJvZCzGl2bIREEP9n2w3Y,34116
|
|
32
31
|
egse/signal.py,sha256=f5pyOiNW9iTSIxV_ce5stIfG0ub9MRbaekE85kQOVzs,7992
|
|
33
|
-
egse/socketdevice.py,sha256=7Q1DstV94pgilOD_e5BnqprTGcXi-XNijdLTw4m4dRY,14726
|
|
34
32
|
egse/state.py,sha256=HdU2MFOlYRbawYRZmizV6Y8MgnZrUF0bx4fXaYU-M_s,3023
|
|
35
|
-
egse/system.py,sha256=
|
|
33
|
+
egse/system.py,sha256=DWKOWkqz5HJMW3526VN7wbMAQv1_EuY3oNeavEydUak,77517
|
|
36
34
|
egse/task.py,sha256=ODSLE05f31CgWsSVcVFFq1WYUZrJMb1LioPTx6VM824,2804
|
|
37
|
-
egse/version.py,sha256=
|
|
35
|
+
egse/version.py,sha256=vPUsCy9HYR7nKm0Sg6EDoq1JtkBKPCr3kYrt9QYM1B8,6602
|
|
38
36
|
egse/zmq_ser.py,sha256=YJFupsxuvhI8TJMeS2Hem9oMMcVmSBx0rZv93gvN-hA,3263
|
|
39
|
-
egse/plugins/metrics/duckdb.py,sha256=E2eeNo3I7ajRuByodaYiPNvC0Zwyc7hsIlhr1W_eXdo,16148
|
|
40
37
|
egse/plugins/metrics/influxdb.py,sha256=WnAqTWRkAyMSd7W2ASwUAIEwFborrv55iX-umceevFA,8162
|
|
41
|
-
|
|
42
|
-
cgse_common-0.17.
|
|
43
|
-
cgse_common-0.17.
|
|
44
|
-
cgse_common-0.17.
|
|
45
|
-
cgse_common-0.17.1.dist-info/RECORD,,
|
|
38
|
+
cgse_common-0.17.3.dist-info/METADATA,sha256=tlkWJwh-TWW4AEBHyzl5lDiXk_awl34jJcDiD08bpuI,3068
|
|
39
|
+
cgse_common-0.17.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
40
|
+
cgse_common-0.17.3.dist-info/entry_points.txt,sha256=xJsPRIDjtADVgd_oEDHVW10wS5LG30Ox_3brVKeyCGw,168
|
|
41
|
+
cgse_common-0.17.3.dist-info/RECORD,,
|
egse/bits.py
CHANGED
|
@@ -5,7 +5,6 @@ This module contains a number of convenience functions to work with bits, bytes
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import ctypes
|
|
8
|
-
from collections.abc import Iterable
|
|
9
8
|
from typing import Union
|
|
10
9
|
|
|
11
10
|
|
|
@@ -33,7 +32,7 @@ def extract_bits(value: int, start_position: int, num_bits: int) -> int:
|
|
|
33
32
|
return extracted_bits
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
def set_bit(value: int, bit) -> int:
|
|
35
|
+
def set_bit(value: int, bit: int) -> int:
|
|
37
36
|
"""
|
|
38
37
|
Set bit to 1 for the given value.
|
|
39
38
|
|
|
@@ -47,7 +46,7 @@ def set_bit(value: int, bit) -> int:
|
|
|
47
46
|
return value | (1 << bit)
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
def set_bits(value: int, bits: tuple) -> int:
|
|
49
|
+
def set_bits(value: int, bits: tuple[int, int]) -> int:
|
|
51
50
|
"""
|
|
52
51
|
Set the given bits in value to 1.
|
|
53
52
|
|
|
@@ -63,7 +62,7 @@ def set_bits(value: int, bits: tuple) -> int:
|
|
|
63
62
|
return value
|
|
64
63
|
|
|
65
64
|
|
|
66
|
-
def clear_bit(value: int, bit) -> int:
|
|
65
|
+
def clear_bit(value: int, bit: int) -> int:
|
|
67
66
|
"""
|
|
68
67
|
Set bit to 0 for the given value.
|
|
69
68
|
|
|
@@ -77,7 +76,7 @@ def clear_bit(value: int, bit) -> int:
|
|
|
77
76
|
return value & ~(1 << bit)
|
|
78
77
|
|
|
79
78
|
|
|
80
|
-
def clear_bits(value: int, bits: tuple) -> int:
|
|
79
|
+
def clear_bits(value: int, bits: tuple[int, int]) -> int:
|
|
81
80
|
"""
|
|
82
81
|
Set the given bits in value to 0.
|
|
83
82
|
|
|
@@ -93,7 +92,7 @@ def clear_bits(value: int, bits: tuple) -> int:
|
|
|
93
92
|
return value
|
|
94
93
|
|
|
95
94
|
|
|
96
|
-
def toggle_bit(value: int, bit) -> int:
|
|
95
|
+
def toggle_bit(value: int, bit: int) -> int:
|
|
97
96
|
"""
|
|
98
97
|
Toggle the bit in the given value.
|
|
99
98
|
|
|
@@ -107,7 +106,7 @@ def toggle_bit(value: int, bit) -> int:
|
|
|
107
106
|
return value ^ (1 << bit)
|
|
108
107
|
|
|
109
108
|
|
|
110
|
-
def bit_set(value: int, bit) -> bool:
|
|
109
|
+
def bit_set(value: int, bit: int) -> bool:
|
|
111
110
|
"""
|
|
112
111
|
Return True if the bit is set.
|
|
113
112
|
|
|
@@ -122,27 +121,25 @@ def bit_set(value: int, bit) -> bool:
|
|
|
122
121
|
return value & bit_value == bit_value
|
|
123
122
|
|
|
124
123
|
|
|
125
|
-
def bits_set(value: int, *args:
|
|
124
|
+
def bits_set(value: int, *args: int) -> bool:
|
|
126
125
|
"""
|
|
127
126
|
Return True if all the bits are set.
|
|
128
127
|
|
|
129
128
|
Args:
|
|
130
129
|
value (int): the value to check
|
|
131
130
|
args: a set of indices of the bits to check, starting from 0 at the LSB.
|
|
132
|
-
All the indices
|
|
133
|
-
|
|
131
|
+
All the indices shall be given as separate arguments, i.e. unpack a list
|
|
132
|
+
if needed.
|
|
134
133
|
|
|
135
134
|
Returns:
|
|
136
135
|
True if all the bits are set (1).
|
|
137
136
|
|
|
138
137
|
Examples:
|
|
139
|
-
>>> assert bits_set(0b0101_0000_1011,
|
|
140
|
-
>>> assert bits_set(0b0101_0000_1011,
|
|
141
|
-
>>> assert not bits_set(0b0101_0000_1011, [1, 2, 3])
|
|
138
|
+
>>> assert bits_set(0b0101_0000_1011, 0, 1, 3, 8, 10)
|
|
139
|
+
>>> assert bits_set(0b0101_0000_1011, 3, 8)
|
|
140
|
+
>>> assert not bits_set(0b0101_0000_1011, *[1, 2, 3])
|
|
142
141
|
"""
|
|
143
142
|
|
|
144
|
-
if len(args) == 1 and isinstance(args[0], list):
|
|
145
|
-
args = args[0]
|
|
146
143
|
return all([bit_set(value, bit) for bit in args])
|
|
147
144
|
|
|
148
145
|
|
|
@@ -506,7 +503,7 @@ def crc_calc(data: list[bytes | int], start: int, len_: int) -> int:
|
|
|
506
503
|
Reference:
|
|
507
504
|
The description of the CRC calculation for RMAP is given in the ECSS document
|
|
508
505
|
_Space Engineering: SpaceWire - Remote Memory Access Protocol_, section A.3
|
|
509
|
-
on page 80 [ECSS
|
|
506
|
+
on page 80 [ECSS-E-ST-50-52C].
|
|
510
507
|
|
|
511
508
|
"""
|
|
512
509
|
crc: int = 0
|
|
@@ -548,7 +545,7 @@ def s16(value: int) -> int:
|
|
|
548
545
|
>>> s16(0b1000_0000_0001_0001)
|
|
549
546
|
-32751
|
|
550
547
|
|
|
551
|
-
The 'bin()'
|
|
548
|
+
The 'bin()' function will return a strange representation of this number:
|
|
552
549
|
|
|
553
550
|
>>> bin(-32751)
|
|
554
551
|
'-0b111111111101111'
|
egse/decorators.py
CHANGED
|
@@ -15,8 +15,8 @@ from typing import Optional
|
|
|
15
15
|
|
|
16
16
|
import rich
|
|
17
17
|
|
|
18
|
-
from egse.system import get_caller_info
|
|
19
18
|
from egse.log import logger
|
|
19
|
+
from egse.system import get_caller_info
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def static_vars(**kwargs):
|
|
@@ -316,7 +316,10 @@ def debug(func):
|
|
|
316
316
|
|
|
317
317
|
|
|
318
318
|
def profile_func(
|
|
319
|
-
output_file: str
|
|
319
|
+
output_file: str | None = None,
|
|
320
|
+
sort_by: str = "cumulative",
|
|
321
|
+
lines_to_print: int | None = None,
|
|
322
|
+
strip_dirs: bool = False,
|
|
320
323
|
) -> Callable:
|
|
321
324
|
"""A time profiler decorator.
|
|
322
325
|
|
|
@@ -346,7 +349,7 @@ def profile_func(
|
|
|
346
349
|
decorator](https://gist.github.com/ekhoda/2de44cf60d29ce24ad29758ce8635b78).
|
|
347
350
|
|
|
348
351
|
Inspired by and modified the profile decorator of Giampaolo Rodola:
|
|
349
|
-
[profile
|
|
352
|
+
[profile decorator](http://code.activestate.com/recipes/577817-profile-decorator/).
|
|
350
353
|
|
|
351
354
|
|
|
352
355
|
"""
|
egse/device.py
CHANGED
|
@@ -339,76 +339,6 @@ class AsyncDeviceTransport:
|
|
|
339
339
|
return await self.trans(command)
|
|
340
340
|
|
|
341
341
|
|
|
342
|
-
class AsyncDeviceConnectionInterface(DeviceConnectionObservable):
|
|
343
|
-
"""Generic connection interface for all Device classes and Controllers.
|
|
344
|
-
|
|
345
|
-
This interface shall be implemented in the Controllers that directly connect to the
|
|
346
|
-
hardware, but also in the simulators to guarantee an identical interface as the controllers.
|
|
347
|
-
|
|
348
|
-
This interface will be implemented in the Proxy classes through the
|
|
349
|
-
YAML definitions. Therefore, the YAML files shall define at least
|
|
350
|
-
the following commands: `connect`, `disconnect`, `reconnect`, `is_connected`.
|
|
351
|
-
"""
|
|
352
|
-
|
|
353
|
-
def __init__(self):
|
|
354
|
-
super().__init__()
|
|
355
|
-
|
|
356
|
-
def __enter__(self):
|
|
357
|
-
self.connect()
|
|
358
|
-
return self
|
|
359
|
-
|
|
360
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
361
|
-
self.disconnect()
|
|
362
|
-
|
|
363
|
-
async def connect(self) -> None:
|
|
364
|
-
"""Connect to the device controller.
|
|
365
|
-
|
|
366
|
-
Raises:
|
|
367
|
-
ConnectionError: when the connection can not be opened.
|
|
368
|
-
"""
|
|
369
|
-
|
|
370
|
-
raise NotImplementedError
|
|
371
|
-
|
|
372
|
-
async def disconnect(self) -> None:
|
|
373
|
-
"""Disconnect from the device controller.
|
|
374
|
-
|
|
375
|
-
Raises:
|
|
376
|
-
ConnectionError: when the connection can not be closed.
|
|
377
|
-
"""
|
|
378
|
-
raise NotImplementedError
|
|
379
|
-
|
|
380
|
-
async def reconnect(self):
|
|
381
|
-
"""Reconnect the device controller.
|
|
382
|
-
|
|
383
|
-
Raises:
|
|
384
|
-
ConnectionError: when the device can not be reconnected for some reason.
|
|
385
|
-
"""
|
|
386
|
-
raise NotImplementedError
|
|
387
|
-
|
|
388
|
-
async def is_connected(self) -> bool:
|
|
389
|
-
"""Check if the device is connected.
|
|
390
|
-
|
|
391
|
-
Returns:
|
|
392
|
-
True if the device is connected and responds to a command, False otherwise.
|
|
393
|
-
"""
|
|
394
|
-
raise NotImplementedError
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
class AsyncDeviceInterface(AsyncDeviceConnectionInterface):
|
|
398
|
-
"""A generic interface for all device classes."""
|
|
399
|
-
|
|
400
|
-
def is_simulator(self) -> bool:
|
|
401
|
-
"""Checks whether the device is a simulator rather than a real hardware controller.
|
|
402
|
-
|
|
403
|
-
This can be useful for testing purposes or when doing actual movement simulations.
|
|
404
|
-
|
|
405
|
-
Returns:
|
|
406
|
-
True if the Device is a Simulator; False if the Device is connected to real hardware.
|
|
407
|
-
"""
|
|
408
|
-
|
|
409
|
-
raise NotImplementedError
|
|
410
|
-
|
|
411
|
-
|
|
412
342
|
class DeviceFactoryInterface:
|
|
413
343
|
"""
|
|
414
344
|
Base class for creating a device factory class to access devices.
|
egse/env.py
CHANGED
|
@@ -72,8 +72,8 @@ import os
|
|
|
72
72
|
import warnings
|
|
73
73
|
from pathlib import Path
|
|
74
74
|
|
|
75
|
-
from dotenv import load_dotenv as _load_dotenv
|
|
76
75
|
from dotenv import find_dotenv
|
|
76
|
+
from dotenv import load_dotenv as _load_dotenv
|
|
77
77
|
from rich.console import Console
|
|
78
78
|
|
|
79
79
|
from egse.decorators import static_vars
|
|
@@ -697,6 +697,7 @@ def env_var(**kwargs: str | int | float | bool | None):
|
|
|
697
697
|
def main(args: list | None = None): # pragma: no cover
|
|
698
698
|
import argparse
|
|
699
699
|
import sys
|
|
700
|
+
|
|
700
701
|
import rich
|
|
701
702
|
|
|
702
703
|
parser = argparse.ArgumentParser()
|
egse/exceptions.py
CHANGED
egse/log.py
CHANGED
|
@@ -18,6 +18,7 @@ __all__ = [
|
|
|
18
18
|
"LOG_DATE_FORMAT_FULL",
|
|
19
19
|
"LOG_DATE_FORMAT_CLEAN",
|
|
20
20
|
"logger",
|
|
21
|
+
"logging", # export to guarantee that this module is imported and initialized before users use logging
|
|
21
22
|
"root_logger",
|
|
22
23
|
"egse_logger",
|
|
23
24
|
"get_log_level_from_env",
|
|
@@ -84,7 +85,7 @@ class NonEGSEFilter(logging.Filter):
|
|
|
84
85
|
return not record.name.startswith("egse")
|
|
85
86
|
|
|
86
87
|
|
|
87
|
-
def get_log_level_from_env(env_var: str = "LOG_LEVEL", default:
|
|
88
|
+
def get_log_level_from_env(env_var: str = "LOG_LEVEL", default: str = "INFO") -> int:
|
|
88
89
|
"""Read the log level from an environment variable."""
|
|
89
90
|
log_level_str = os.getenv(env_var, default)
|
|
90
91
|
|
|
@@ -95,18 +96,16 @@ def get_log_level_from_env(env_var: str = "LOG_LEVEL", default: int = logging.IN
|
|
|
95
96
|
if 10 <= log_level <= 50:
|
|
96
97
|
return log_level
|
|
97
98
|
else:
|
|
98
|
-
logging.warning(
|
|
99
|
-
|
|
100
|
-
)
|
|
101
|
-
return default
|
|
99
|
+
logging.warning(f"Log level {log_level} outside standard range (10-50). Using {default.upper()}.")
|
|
100
|
+
return logging._nameToLevel[default.upper()]
|
|
102
101
|
|
|
103
102
|
except ValueError:
|
|
104
103
|
log_level_str = log_level_str.upper()
|
|
105
104
|
try:
|
|
106
105
|
return getattr(logging, log_level_str)
|
|
107
106
|
except AttributeError:
|
|
108
|
-
logging.error(f"Invalid LOG_LEVEL '{log_level_str}'. Using {
|
|
109
|
-
return default
|
|
107
|
+
logging.error(f"Invalid LOG_LEVEL '{log_level_str}'. Using {default.upper()}.")
|
|
108
|
+
return logging._nameToLevel[default.upper()]
|
|
110
109
|
|
|
111
110
|
|
|
112
111
|
egse_logger = logging.getLogger("egse")
|
|
@@ -145,7 +144,7 @@ if __name__ == "__main__":
|
|
|
145
144
|
Environment variables:
|
|
146
145
|
- LOG_LEVEL=debug|info|warning|critical
|
|
147
146
|
- LOG_FORMAT=full|clean
|
|
148
|
-
|
|
147
|
+
|
|
149
148
|
Example logging statements
|
|
150
149
|
- logging level set to INFO
|
|
151
150
|
- logging format set to full
|