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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgse-common
3
- Version: 0.17.1
3
+ Version: 0.17.3
4
4
  Summary: Software framework to support hardware testing
5
5
  Author: IvS KU Leuven
6
6
  Maintainer-email: Rik Huygen <rik.huygen@kuleuven.be>, Sara Regibo <sara.regibo@kuleuven.be>
@@ -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=cg6diLN2IwNtnrlZyLgXPfDf9ttcHzS2A7Tjwlwc-lQ,12498
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=RT_-TmcHLN3oqha-1xn-YbqT1tEtKA84zr0Qu1KFyKo,27176
9
- egse/device.py,sha256=Ga5MNE96ERuPLDzmb0HF7UfjrTqfp0f_r3NDVZY9l28,13595
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=2ZeEOyVUp9IANy4S0XK53KUMohelbct7S3lR6iWpeks,31704
12
- egse/exceptions.py,sha256=QB3MZRJizecWOj1cPbvG0UcIqFn7NRJ6rw1xtdNSFxw,1225
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=Q_TviwuyMam6CwRklaJk1lZM5WIZK_L9GS7wWDy_naM,5251
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=4OxgNc7HhQKZ7Gsg_tYstQKw_o4BxH8LVslG_X5ecz8,15965
29
- egse/settings.py,sha256=m95NuhLYdmRK4-SKZ4awhGp4X_6vCcb_yLvm7dmY-Dg,15656
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=3aycoK15UvNdk2yxQ8hx4N-s2Ag4BqTTPQ8eFuJa3Ko,76111
33
+ egse/system.py,sha256=DWKOWkqz5HJMW3526VN7wbMAQv1_EuY3oNeavEydUak,77517
36
34
  egse/task.py,sha256=ODSLE05f31CgWsSVcVFFq1WYUZrJMb1LioPTx6VM824,2804
37
- egse/version.py,sha256=e9GvelUZ9mfCDlRju4MWEJeMHJW9kUzK6SKzJpyj91s,6156
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
- egse/plugins/metrics/timescaledb.py,sha256=Ug0NWDV1Ky2VeFY6tDZL9xg6AFgnAEh2F_llVPnlRBA,21191
42
- cgse_common-0.17.1.dist-info/METADATA,sha256=DKZF-wlYPiRujjFleFHI1IIgWL2GdLDJ3ySq-gOK1xk,3068
43
- cgse_common-0.17.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
44
- cgse_common-0.17.1.dist-info/entry_points.txt,sha256=xJsPRIDjtADVgd_oEDHVW10wS5LG30Ox_3brVKeyCGw,168
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
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: Union[int, Iterable[int]]) -> bool:
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 can be given as separate arguments, or they can be passed
133
- in as a list.
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, [0, 1, 3, 8, 10])
140
- >>> assert bits_set(0b0101_0000_1011, [3, 8])
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 [ECSSEST5052C].
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()' fuction will return a strange representation of this number:
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 = None, sort_by: str = "cumulative", lines_to_print: int = None, strip_dirs: bool = False
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 decorato](http://code.activestate.com/recipes/577817-profile-decorator/).
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
@@ -61,3 +61,6 @@ class Abort(RuntimeError):
61
61
 
62
62
  class InitialisationError(Error):
63
63
  """Raised when an initialisation failed."""
64
+
65
+
66
+ InitializationError = InitialisationError # Alias with American spelling
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: int = logging.INFO):
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
- f"Log level {log_level} outside standard range (10-50). Using {logging.getLevelName(default)}."
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 {logging.getLevelName(default)}.")
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