holado 0.9.3__py3-none-any.whl → 0.10.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.

Potentially problematic release.


This version of holado might be problematic. Click here for more details.

Files changed (48) hide show
  1. holado/__init__.py +24 -6
  2. holado/common/context/session_context.py +5 -4
  3. holado/holado_config.py +4 -1
  4. {holado-0.9.3.dist-info → holado-0.10.1.dist-info}/METADATA +1 -1
  5. {holado-0.9.3.dist-info → holado-0.10.1.dist-info}/RECORD +48 -47
  6. holado_ais/ais/ais_messages.py +33 -3
  7. holado_ais/tests/behave/steps/ais/ais_messages_steps.py +23 -3
  8. holado_core/common/tools/path_manager.py +6 -3
  9. holado_docker/tools/docker_controller/server/rest/run.py +5 -2
  10. holado_docker/tools/docker_viewer/server/rest/run.py +5 -2
  11. holado_logging/common/logging/log_manager.py +71 -29
  12. holado_multitask/multithreading/context/thread_context.py +3 -1
  13. holado_python/standard_library/queue.py +1 -1
  14. holado_python/standard_library/ssl/resources/certificates/tcpbin.crt +16 -16
  15. holado_python/standard_library/ssl/resources/certificates/tcpbin.key +26 -26
  16. holado_scripting/__init__.py +2 -1
  17. holado_scripting/common/tools/variable_manager.py +42 -9
  18. holado_test/common/context/feature_context.py +3 -1
  19. holado_test/common/context/scenario_context.py +3 -1
  20. holado_test/test_server/server/rest/run.py +2 -1
  21. test_holado/environment.py +3 -1
  22. test_holado/features/NonReg/holado_ais/ais_message-bitarray_to_nmea.feature +1 -1
  23. test_holado/features/NonReg/holado_ais/ais_message-nmea_raw_to_dict.feature +93 -0
  24. test_holado/features/NonReg/holado_ais/message_types/type-10.feature +1 -1
  25. test_holado/features/NonReg/holado_ais/message_types/type-12.feature +1 -1
  26. test_holado/features/NonReg/holado_ais/message_types/type-14.feature +1 -1
  27. test_holado/features/NonReg/holado_ais/message_types/type-15.feature +1 -1
  28. test_holado/features/NonReg/holado_ais/message_types/type-16.feature +1 -1
  29. test_holado/features/NonReg/holado_ais/message_types/type-17.feature +1 -1
  30. test_holado/features/NonReg/holado_ais/message_types/type-18.feature +1 -1
  31. test_holado/features/NonReg/holado_ais/message_types/type-19.feature +1 -1
  32. test_holado/features/NonReg/holado_ais/message_types/type-1_2_3.feature +1 -1
  33. test_holado/features/NonReg/holado_ais/message_types/type-20.feature +1 -1
  34. test_holado/features/NonReg/holado_ais/message_types/type-21.feature +1 -1
  35. test_holado/features/NonReg/holado_ais/message_types/type-22.feature +2 -2
  36. test_holado/features/NonReg/holado_ais/message_types/type-23.feature +1 -1
  37. test_holado/features/NonReg/holado_ais/message_types/type-24.feature +2 -2
  38. test_holado/features/NonReg/holado_ais/message_types/type-25.feature +4 -4
  39. test_holado/features/NonReg/holado_ais/message_types/type-26.feature +4 -4
  40. test_holado/features/NonReg/holado_ais/message_types/type-27.feature +1 -1
  41. test_holado/features/NonReg/holado_ais/message_types/type-4_11.feature +1 -1
  42. test_holado/features/NonReg/holado_ais/message_types/type-5.feature +1 -1
  43. test_holado/features/NonReg/holado_ais/message_types/type-6.feature +1 -1
  44. test_holado/features/NonReg/holado_ais/message_types/type-7_13.feature +1 -1
  45. test_holado/features/NonReg/holado_ais/message_types/type-8.feature +1 -1
  46. test_holado/features/NonReg/holado_ais/message_types/type-9.feature +1 -1
  47. {holado-0.9.3.dist-info → holado-0.10.1.dist-info}/WHEEL +0 -0
  48. {holado-0.9.3.dist-info → holado-0.10.1.dist-info}/licenses/LICENSE +0 -0
@@ -39,6 +39,7 @@ class LogManager(object):
39
39
  self.on_console = False
40
40
  self.__console_handler = None
41
41
 
42
+ # Manage file handlers
42
43
  self.in_file = True
43
44
  self.__files_lock = threading.Lock()
44
45
  self.__file_names = []
@@ -47,20 +48,26 @@ class LogManager(object):
47
48
  self.__root_file_handler = None
48
49
  self.__root_file_handler_active = False
49
50
 
51
+ # Manage file paths LIFO by loggers
52
+ self.__files_by_logger = {}
53
+
50
54
  # Initialize format according python version
51
55
  from holado_multitask.multitasking.multitask_manager import MultitaskManager
52
56
  if MultitaskManager.has_thread_native_id():
53
57
  # Exists since python 3.8
54
58
  # self.format = '{asctime:s} | {thread_native_id:-5d} | {levelname:5s} | {name:50s} | {message:s}'
55
59
  self.format = '{asctime:s} | {process:-5d}-{thread_native_id:-5d} | {levelname:5s} | {name:50s} | {message:s}'
60
+ self.format_short = '{asctime:s} | {message:s}'
56
61
  self.style = '{'
57
62
  else:
58
63
  if sys.version_info > (3, 2):
59
64
  # self.format = '{asctime:s} | {thread:-5d} | {levelname:5s} | {module:35s} | {message:s}'
60
65
  self.format = '{asctime:s} | {process:-5d}-{thread:-5d} | {levelname:5s} | {name:50s} | {message:s}'
66
+ self.format_short = '{asctime:s} | {message:s}'
61
67
  self.style = '{'
62
68
  else:
63
69
  self.format = '%(asctime)s | %(process)-5d-%(thread)-5d | %(levelname)5s | %(module)35s | %(message)s'
70
+ self.format_short = '%(asctime)s | %(message)s'
64
71
  self.style = '%'
65
72
 
66
73
  def configure(self):
@@ -193,7 +200,6 @@ class LogManager(object):
193
200
 
194
201
  def add_root_file_handler(self):
195
202
  from holado_core.common.exceptions.technical_exception import TechnicalException
196
- from holado_multitask.multitasking.multitask_manager import MultitaskManager
197
203
 
198
204
  logger_ = logging.getLogger()
199
205
 
@@ -201,13 +207,8 @@ class LogManager(object):
201
207
  raise TechnicalException("Root log file is not defined")
202
208
 
203
209
  if self.__root_file_handler is None:
204
- logger_.info("Creating file handler to root file '{}'.".format(self.__root_file_name))
205
- Path(os.path.dirname(self.__root_file_name)).mkdir(parents=True, exist_ok=True)
206
-
207
- self.__root_file_handler = logging.FileHandler(self.__root_file_name, mode='w', encoding='utf8')
208
- self.__root_file_handler.setFormatter(logging.Formatter(fmt=self.format, style=self.style))
209
- if MultitaskManager.has_thread_native_id():
210
- self.__root_file_handler.addFilter(filter_thread_native_id)
210
+ logger.info("Creating file handler to root file '{}'.".format(self.__root_file_name))
211
+ self.__root_file_handler = self.__new_file_handler(self.__root_file_name)
211
212
 
212
213
  logger_.addHandler(self.__root_file_handler)
213
214
  self.__root_file_handler_active = True
@@ -215,15 +216,13 @@ class LogManager(object):
215
216
  def remove_root_file_handler(self, do_reset=False):
216
217
  logger_ = logging.getLogger()
217
218
  if self.__root_file_handler:
218
- logger_.info(f"Removing log destination to root file '{self.__root_file_name}'.")
219
+ logger.info(f"Removing log destination to root file '{self.__root_file_name}'.")
219
220
  logger_.removeHandler(self.__root_file_handler)
220
221
  self.__root_file_handler_active = False
221
222
  if do_reset:
222
223
  self.__root_file_handler = None
223
224
 
224
225
  def add_file_handler(self, file_name, logger_=None):
225
- from holado_multitask.multitasking.multitask_manager import MultitaskManager
226
-
227
226
  if logger_ is None:
228
227
  logger_ = logging.getLogger()
229
228
 
@@ -232,35 +231,59 @@ class LogManager(object):
232
231
  self.add_log_file(file_name)
233
232
 
234
233
  if file_name in self.__file_handlers:
235
- logger_.debug("Log destination already set to file '{}'.".format(file_name))
234
+ logger.debug("Log destination already set to file '{}'.".format(file_name))
236
235
  else:
237
- logger_.info("Adding log destination to file '{}'.".format(file_name))
238
- Path(os.path.dirname(file_name)).mkdir(parents=True, exist_ok=True)
239
-
240
- file_handler = logging.FileHandler(file_name, mode='w', encoding='utf8')
241
- file_handler.setFormatter(logging.Formatter(fmt=self.format, style=self.style))
242
- if MultitaskManager.has_thread_native_id():
243
- file_handler.addFilter(filter_thread_native_id)
244
-
236
+ logger.info("Adding log destination to file '{}'.".format(file_name))
237
+ file_handler = self.__new_file_handler(file_name)
245
238
  self.__file_handlers[file_name] = file_handler
246
- logger_.addHandler(file_handler)
247
-
248
- def remove_file_handler(self, file_name, logger_=None, do_remove_log_file=True):
249
- from holado_core.common.exceptions.technical_exception import TechnicalException
239
+ self.add_existing_file_handler_to_logger(file_name, logger_)
240
+
241
+ def __new_file_handler(self, file_path, use_format_short=False):
242
+ from holado_multitask.multitasking.multitask_manager import MultitaskManager
243
+
244
+ Path(os.path.dirname(file_path)).mkdir(parents=True, exist_ok=True)
245
+
246
+ res = logging.FileHandler(file_path, mode='w', encoding='utf8')
247
+ fmt = self.format_short if use_format_short else self.format
248
+ res.setFormatter(logging.Formatter(fmt=fmt, style=self.style))
249
+ if MultitaskManager.has_thread_native_id():
250
+ res.addFilter(filter_thread_native_id)
250
251
 
252
+ return res
253
+
254
+ def remove_file_handler(self, file_name, logger_=None, do_remove_log_file=True):
251
255
  if logger_ is None:
252
256
  logger_ = logging.getLogger()
253
257
 
254
- if file_name not in self.__file_handlers:
255
- raise TechnicalException(f"Not set log destination to file '{file_name}'")
256
-
257
- logger_.info("Removing log destination to file '{}'.".format(file_name))
258
- logger_.removeHandler(self.__file_handlers[file_name])
258
+ logger.info("Removing log destination to file '{}'.".format(file_name))
259
+ self.remove_existing_file_handler_from_logger(file_name, logger_)
259
260
  del self.__file_handlers[file_name]
260
261
 
261
262
  if do_remove_log_file:
262
263
  self.remove_log_file(file_name)
263
264
 
265
+ def add_existing_file_handler_to_logger(self, file_name, logger_):
266
+ from holado_core.common.exceptions.technical_exception import TechnicalException
267
+
268
+ if self.__root_file_name == file_name:
269
+ file_handler = self.__root_file_handler
270
+ else:
271
+ if file_name not in self.__file_handlers:
272
+ raise TechnicalException(f"Not set log destination to file '{file_name}'")
273
+ file_handler = self.__file_handlers[file_name]
274
+ logger_.addHandler(file_handler)
275
+
276
+ def remove_existing_file_handler_from_logger(self, file_name, logger_):
277
+ from holado_core.common.exceptions.technical_exception import TechnicalException
278
+
279
+ if self.__root_file_name == file_name:
280
+ file_handler = self.__root_file_handler
281
+ else:
282
+ if file_name not in self.__file_handlers:
283
+ raise TechnicalException(f"Not set log destination to file '{file_name}'")
284
+ file_handler = self.__file_handlers[file_name]
285
+ logger_.removeHandler(file_handler)
286
+
264
287
  def __remove_existing_file_handlers(self, log_level_if_exists=None):
265
288
  with self.__files_lock:
266
289
  if len(self.__file_names) > 0:
@@ -289,5 +312,24 @@ class LogManager(object):
289
312
  self.add_root_file_handler()
290
313
  self.remove_file_handler(file_name, do_remove_log_file=do_remove_log_file)
291
314
 
315
+ def enter_log_file_for_logger(self, logger_, file_path, use_format_short=False, switch_in=True):
316
+ logger_name = logger_.name
317
+ if logger_name not in self.__files_by_logger:
318
+ self.__files_by_logger[logger_name] = []
319
+
320
+ if switch_in and len(self.__files_by_logger[logger_name]) > 0:
321
+ logger_.removeHandler(self.__files_by_logger[logger_name][-1][1])
322
+
323
+ file_handler = self.__new_file_handler(file_path, use_format_short=use_format_short)
324
+ logger_.addHandler(file_handler)
325
+ self.__files_by_logger[logger_name].append( (file_path, file_handler) )
326
+
327
+ def leave_log_file_for_logger(self, logger_, switch_out=True):
328
+ logger_name = logger_.name
329
+ _, file_handler = self.__files_by_logger[logger_name].pop()
330
+ logger_.removeHandler(file_handler)
331
+
332
+ if switch_out and len(self.__files_by_logger[logger_name]) > 0:
333
+ logger_.addHandler(self.__files_by_logger[logger_name][-1][1])
292
334
 
293
335
 
@@ -61,7 +61,9 @@ class ThreadContext(Context):
61
61
 
62
62
  manager = VariableManager(var_man)
63
63
  self.set_object("variable_manager", manager)
64
- manager.initialize(SessionContext.instance().dynamic_text_manager, SessionContext.instance().unique_value_manager)
64
+ file_path = SessionContext.instance().report_manager.get_path("logs", f"variable_update-thread_{self.thread_uid}.log")
65
+ manager.initialize(SessionContext.instance().dynamic_text_manager, SessionContext.instance().unique_value_manager,
66
+ variable_update_log_file_path=file_path)
65
67
  return self.get_object("variable_manager")
66
68
 
67
69
 
@@ -61,7 +61,7 @@ class IterableQueue(queue.Queue, typing.Iterable):
61
61
 
62
62
 
63
63
  class IterableLifoQueue(IterableQueue):
64
- '''Copyt of implementation of queue.LifoQueue but inheriting of IterableQueue.'''
64
+ '''Copy of implementation of queue.LifoQueue but inheriting of IterableQueue.'''
65
65
 
66
66
  def _init(self, maxsize):
67
67
  self.queue = []
@@ -2,20 +2,20 @@
2
2
  MIIDZTCCAk2gAwIBAgIBKjANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMCVVMx
3
3
  CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKDAZ0
4
4
  Y3BiaW4xDDAKBgNVBAsMA29wczETMBEGA1UEAwwKdGNwYmluLmNvbTEjMCEGCSqG
5
- SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUxMDAyMTMzNjQ1WhcN
6
- MjUxMDAzMTMzNjQ1WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
- DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2xah/MsJKGnIpj84nYfBRCeAh8
8
- MmN5dZwUCteehkX+wFhioEx1loAIqcqs6MPe7qQdeROuOZlGeiDR/6X0mnDsgyR4
9
- qUnrIaRHS3EFWGtGp0WRLsQhKNvtxAHL7dErz7BoxTO5gV/w6dcT3uPORfZxkZdm
10
- 6t01t7DwPFktopQju9E8eeMBKVKaO1RrclZKkWEyfuHP3wNpIE6GwsH8jCn4I+r/
11
- Y8Pgd+k4EyCaH+ngtFbS0lEhxxuqTpPRYyQrlEDMa1i/nETuMiL2WFkjEO2gEX/p
12
- w05GlO3YUTDpaXWUWZf+Ck7MYevrFDC57oSZvMwTn5pJrQztvNJjFc+YF6kCAwEA
13
- AaNCMEAwHQYDVR0OBBYEFLuHuKWOQ/U1+OpiGgffNV1faI9qMB8GA1UdIwQYMBaA
14
- FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQBYIRlg6Paz
15
- ALTKoBm8nRB19n4d7Ay+U1bUBCP2U5vZkUTSu05ttQXT72TaFIaT04pFs9uIHGFZ
16
- 9yhP2DgbuCaexQrvf9yf6nnoCqLjlhJ8Y0NmscK14Hp9GgVSnkXeweL82gFsXB45
17
- FaqqyDn20QiH14nwU2H7g8y/Ys0PIemhjG8UT7OjSLyhkaCkxwYy88N/2YjX3hGH
18
- 9eTHvfMZ+9E7Urh3DevivhfPQnX/6lUAOK7Sr+WTIEjpZ89Lz/rLltRCXoXv75C4
19
- PdRoxB2/lo+3+X1i4B7ujaduZDLaMyPcckbpuTYxjPZtoxhLyYkKgzQTUMwYsVrW
20
- DoI6HuqlfzoH
5
+ SIb3DQEJARYUaGFycnliYWdkaUBnbWFpbC5jb20wHhcNMjUxMDE2MjIzNTE5WhcN
6
+ MjUxMDE3MjIzNTE5WjAcMRowGAYDVQQDDBF0Y3BiaW4uY29tLWNsaWVudDCCASIw
7
+ DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxmg8CRudZQj9pgRnvPQrWyqn1A
8
+ 55RlXoax8OMEeEQHhreCOj69WV6K9OvHebbAtMNCEyXFwNUNX1XjlhhLcqhY5yLR
9
+ 5k9vgOoq2ribBwdMRnYyIajWp7y53L/J35Qf2FWNeS+3AXv/mWiYnGpTJZHXCMyo
10
+ wOgDqeqz5wzl8ncvj5HWBkZm/mPDwK6fR/4SXMv+NIBooUKGZTST/1Q75/tvPhwf
11
+ dpGWTUd1xKw3TKz63B+jAATdPbIxTnSxJY1uLdBZ1hUguGxrC+nvqgY0283lVz3n
12
+ Jz7P2BCwmwmgRwBLIUw1381QuFJjGlKSglw/HraIfVyJASQqEk2gVil5Gr8CAwEA
13
+ AaNCMEAwHQYDVR0OBBYEFMQRuiY7hUUnl5wxL6R6gnlhyXaiMB8GA1UdIwQYMBaA
14
+ FOLuMowBSAZfV5v82LmlaIIOvU/DMA0GCSqGSIb3DQEBCwUAA4IBAQBAX/CniZsN
15
+ 9YWuDt7CS+YBpLRe46ryZXzmACpmz4uDzRs+3MRnCtOz1121dW0+zuPMdopxwjG2
16
+ GyPirI1mDasoJDn5jRWP1NBvuFN7fcAVsMDi3vBMfzd+oV4Pcgi7uydcd0zX+onp
17
+ 1QIyNwAulQB03gfe6IcPAUwyTOtJoc7yo1W6eH/W+RGmj5BaUP+5SB3EHjqih6ds
18
+ xPc4yJ43N1gYsXRZDoYuqmy+/h0JQmFupPJRAbOFbh3IsunbLXvsKXzlrgKlhsCg
19
+ H0Kc97t7ZQNCzgymNnxsbepNddWwGF8hAj4FruFYtO9rt00aT2bqb9Yw4pRJ+fM8
20
+ nDVx1r7BCieF
21
21
  -----END CERTIFICATE-----
@@ -1,28 +1,28 @@
1
1
  -----BEGIN PRIVATE KEY-----
2
- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtsWofzLCShpyK
3
- Y/OJ2HwUQngIfDJjeXWcFArXnoZF/sBYYqBMdZaACKnKrOjD3u6kHXkTrjmZRnog
4
- 0f+l9Jpw7IMkeKlJ6yGkR0txBVhrRqdFkS7EISjb7cQBy+3RK8+waMUzuYFf8OnX
5
- E97jzkX2cZGXZurdNbew8DxZLaKUI7vRPHnjASlSmjtUa3JWSpFhMn7hz98DaSBO
6
- hsLB/Iwp+CPq/2PD4HfpOBMgmh/p4LRW0tJRIccbqk6T0WMkK5RAzGtYv5xE7jIi
7
- 9lhZIxDtoBF/6cNORpTt2FEw6Wl1lFmX/gpOzGHr6xQwue6EmbzME5+aSa0M7bzS
8
- YxXPmBepAgMBAAECggEBAIqgeMTch2jKyxGg6HTyNUWuL0MGbOj7vaROUsD4os4m
9
- nrlsLegYSX/yaiF6k2QQ/4I4i7Prb8kneL3NHS8E5GaQPbLUIrj+UyFcTZfs3j7w
10
- avyY/SxIEuZFBBUy/6HcR6zSUeIQgnNiQiAImfJTZX9l8P9Xgsf+4Zb0hhXe2E1G
11
- TqLAYWnLoxD9us0rryQb37mRIREKcTO3qza+FXk32bWe83f1Dy46JJIChIoQg/QB
12
- hwzSL51ld22fy7p+bsqeI3HUDWHplq4T0lws0SGUd4IvntF9rNGYHAI+aUKwiUBC
13
- g/0se9+GBKeMSjhS11F9/Clg4i0E/tN/poOytA83aAECgYEA3+E0bhbaFAvzzevv
14
- tAWSXkwHSFZ745KsJSJ8OOVkd+ATleyGl3AoRTrDxNqY+R/TvBFaTyiY+zqGV6tj
15
- NI8SaSXuhRzbA9zDL2rSH7GIOeqzUs8PSUMk6JnmfCKk+aTBOoi8ULolHE4N6B45
16
- te3GVgy/luJK22pPLCMsmL+D0ykCgYEAxpzr8T2CPVtl33W+loGbvrqZ1xXgq/7n
17
- IsjHZdVdFsIIxFhtE2A2iO/7vMsLmwkZ7LgbtHcfEPOxjx5VzVt89l1I2lnP0jW+
18
- pjKrN/eyXcHnWLLPCEtXA06oIvyem/VMSGXumu7EcOJZjnG3/PmqCWCjc2UUo2lJ
19
- F2rQdC9bMIECgYEAl3nSdaI0j1e+79bw6kbSz8Z1LvaFAGce3klE72IV5h3QYqIU
20
- NqaGOMEX8DtPQU/NfPPovKJlT6Y7e1nU15zuAgLOLXZmoWhfD9ggr5z45Obtydub
21
- JiCt+ksW7WqrYNWef7JAaAZqUYpmUmUQ+w0UIuihQL9/kpGNW/m4lOkPknECgYAI
22
- gbodWAwXAq4nVwy1t5FrJuTl8HryAvX1aHIZ63yUN/VWK49ocAuF6/l1SaESn94r
23
- ZGtTXHLJMBbf0WXNaOi+SJqRN52OHF0xEySAPiy2lVKKWwZBDbEJZDoRXY6RkX0V
24
- 8L+6hRWG3DsHvdkqjar5wdjeXWr34M+PoDSTdV/LgQKBgFAqJc4I91AK8Ah9Ba8k
25
- LqYtRFGFJ2J+p8QqcibfT6d6tZqWffxiXbQ5bS52/fmM3BdxEHjtzLdA7cOqCh6g
26
- 79kxRb3B5jjq5JvGtLy89VphZ08W9dhzgL/l3KGtgMobfTYUEDaNk33oExhItQnx
27
- F97ecAMIx20oqFFOg6N0unwW
2
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMZoPAkbnWUI/a
3
+ YEZ7z0K1sqp9QOeUZV6GsfDjBHhEB4a3gjo+vVleivTrx3m2wLTDQhMlxcDVDV9V
4
+ 45YYS3KoWOci0eZPb4DqKtq4mwcHTEZ2MiGo1qe8udy/yd+UH9hVjXkvtwF7/5lo
5
+ mJxqUyWR1wjMqMDoA6nqs+cM5fJ3L4+R1gZGZv5jw8Cun0f+ElzL/jSAaKFChmU0
6
+ k/9UO+f7bz4cH3aRlk1HdcSsN0ys+twfowAE3T2yMU50sSWNbi3QWdYVILhsawvp
7
+ 76oGNNvN5Vc95yc+z9gQsJsJoEcASyFMNd/NULhSYxpSkoJcPx62iH1ciQEkKhJN
8
+ oFYpeRq/AgMBAAECggEAUKjruSRIl6A3BFAVwGnrw1P8H21rdY4DHVg+3Pc4lm/5
9
+ 45TKc1O5XqurNxgCmfG144/BiphdHjYmtvgWlQPA/VoH7B+0qQgxcTb0FQFoZqLc
10
+ 82uZCM2cZ8dYq354cjWW4zvu5LttJIea/EGtB/BD1SdsW4cEiQpZFTtlJBvh8NHo
11
+ 7+o0mPwwBrXmadsLlxDmhQ0Wsw4ltaK7eMBJlLalg9f/3uW4ArW0OXVK1ycszNXM
12
+ 2pfrp9zKYcPzWEP+wrC/6f+AXFDacUIzwxsfNtlI7O57t8pQXf5pkyeBHHlxCvN/
13
+ XYx+UBWip6tRnlZRqNvl/8NC0JpX9P8xaeNp21haAQKBgQD1rlkZ9umlmC9PB5oc
14
+ Tp00KC5KQmgfqRfEBEVzmm4yGHK0OMx0pCnP/ZONZaE4QX4TmeLCnUxgYCdxl6ep
15
+ 406g0i2ig7M+RZ18skh4ubpoiQlLIoNW2mOpV/Hzt53st0HAYogPubrVZAnn/KwA
16
+ zehlj0w1yljBXDsK9c6deCdIgQKBgQDU/E12s8aCC0ngOSZqe0lkDWU/yQfX8BnJ
17
+ cSA3dU1mwGzP+02N5AXZuxwUql1rjE45ERPISQ2+eHtUk3n7QH0+7KNRmj7Jk9xC
18
+ QIN5lExdO3tAXo/muH6PCkyeNrkRSdfNgssYMVJZqbD8O5IM6v6yEbQHOxuskvvu
19
+ uWRxQZTDPwKBgEfqcUqYbGx8z9xibUo7+Oh7mpFCPxiFdt96IJpmajtfzLPUrIS4
20
+ SUUJBVgul7LP+Qfj0+0D/od3nhQyQHIKh8mrvJAF3UItPpxx06UDOP3An2fPAoM6
21
+ ClJX3AtrhF72hdi6/vkbdQVh80RlQjQ6Ef0opTZZtQFk7iOXMJQHx/gBAoGAahxl
22
+ T41Tifirzq1KaWSQ9OsDlZrHcJrrjgPxZA/qBxY5YAk440dGbuqcm+Mg9fMKCb5r
23
+ V66lzU5jS4jKDhZcD9x/pakuPOmQo+VWW106Cn0W88Po967VRth/wZdL7sQWYwoV
24
+ uzDfcVJsnc3j/tGZIQhW4/9b00fLgm0VEKP2xKsCgYEAkylyhMcTA9nuiBGecBFW
25
+ fRbuL6tWcnj3b8lnNOoBFTp6uVSi7VTYcZttGP7zLa9v/LRegawpf1meOarn80Wo
26
+ pz1Ot3ZEgx6iArdgdejSHbps58dTpoXp6YBlZR08G5tw2aHfppJYq2Vz3RLrv5Kf
27
+ k6MQ4yJFgkb+8+cpvp3NxgA=
28
28
  -----END PRIVATE KEY-----
@@ -27,7 +27,8 @@ def register():
27
27
  from holado_scripting.common.tools.variable_manager import VariableManager
28
28
  SessionContext.instance().services.register_service_type("variable_manager", VariableManager,
29
29
  lambda m: m.initialize(SessionContext.instance().dynamic_text_manager,
30
- SessionContext.instance().unique_value_manager) )
30
+ SessionContext.instance().unique_value_manager,
31
+ variable_update_log_file_path=SessionContext.instance().report_manager.get_path("logs", "variable_update.log") ) )
31
32
 
32
33
 
33
34
  from holado_scripting.common.tools.expression_evaluator import ExpressionEvaluator
@@ -22,8 +22,10 @@ from typing import NamedTuple
22
22
  import threading
23
23
  from holado.common.tools.gc_manager import GcManager
24
24
  from holado_python.standard_library.typing import Typing
25
+ from holado.common.context.session_context import SessionContext
25
26
 
26
27
  logger = logging.getLogger(__name__)
28
+ # logger_update = logging.getLogger(__name__ + ".update")
27
29
 
28
30
 
29
31
  class VariableManager(DeleteableObject):
@@ -46,9 +48,22 @@ class VariableManager(DeleteableObject):
46
48
  self.__temporary_variables_lock = threading.Lock()
47
49
  self.__temporary_variables = {}
48
50
 
49
- def initialize(self, dynamic_text_manager, unique_value_manager):
51
+ # Manage variable update log file
52
+ self.__variable_update_log_file_path = None
53
+ self.__is_entered_in_variable_update_log_file = False
54
+ self.__logger_update = logging.getLogger(__name__ + f".update.{id(self)}")
55
+
56
+ def initialize(self, dynamic_text_manager, unique_value_manager, variable_update_log_file_path=None):
57
+ """ Initialize variable manager
58
+ @param dynamic_text_manager Dynamic text manager instance to use
59
+ @param unique_value_manager Unique value manager instance to use
60
+ @param variable_update_log_filename If defined, log all variable updates in given file in addition to normal logs
61
+ """
50
62
  self.__dynamic_text_manager = dynamic_text_manager
51
63
  self.__unique_value_manager = unique_value_manager
64
+
65
+ # Manage variable update log file
66
+ self.__variable_update_log_file_path = variable_update_log_file_path
52
67
 
53
68
  @property
54
69
  def parent(self):
@@ -71,6 +86,19 @@ class VariableManager(DeleteableObject):
71
86
  # # Clear variables
72
87
  # self.__variables.clear()
73
88
 
89
+ # Leave variable update log file
90
+ self.__leave_variable_update_log_file()
91
+
92
+ def __enter_variable_update_log_file(self):
93
+ if self.__variable_update_log_file_path is not None and not self.__is_entered_in_variable_update_log_file:
94
+ SessionContext.instance().log_manager.enter_log_file_for_logger(self.__logger_update, self.__variable_update_log_file_path, use_format_short=True)
95
+ self.__is_entered_in_variable_update_log_file = True
96
+
97
+ def __leave_variable_update_log_file(self):
98
+ if self.__variable_update_log_file_path is not None and self.__is_entered_in_variable_update_log_file:
99
+ SessionContext.instance().log_manager.leave_log_file_for_logger(self.__logger_update)
100
+ self.__is_entered_in_variable_update_log_file = False
101
+
74
102
  @contextmanager
75
103
  def temporary_variables(self):
76
104
  from holado_multitask.multitasking.multitask_manager import MultitaskManager
@@ -125,6 +153,7 @@ class VariableManager(DeleteableObject):
125
153
  def register_variable(self, variable_name, value, accept_expression=True, log_level=logging.INFO):
126
154
  from holado_multitask.multitasking.multitask_manager import MultitaskManager
127
155
 
156
+ self.__enter_variable_update_log_file()
128
157
  if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
129
158
  logger.trace(f"Setting variable: {variable_name}=[{value}] (type: {Typing.get_object_class_fullname(value)})...")
130
159
 
@@ -134,13 +163,13 @@ class VariableManager(DeleteableObject):
134
163
  self.register_variable(names[0], Object())
135
164
  var = self.get_value(names[0], through_patent=False)
136
165
  setattr(var, names[1], value)
137
- if Tools.do_log(logger, log_level):
138
- logger.log(log_level, f"Set variable expression: {variable_name}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
166
+ if Tools.do_log(self.__logger_update, log_level):
167
+ self.__logger_update.log(log_level, f"Set variable expression: {variable_name}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
139
168
  else:
140
169
  var_name = self.evaluate_variable_name(variable_name)
141
170
  self.__variables[var_name] = value
142
- if Tools.do_log(logger, log_level):
143
- logger.log(log_level, f"Set variable: {var_name}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
171
+ if Tools.do_log(self.__logger_update, log_level):
172
+ self.__logger_update.log(log_level, f"Set variable: {var_name}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
144
173
 
145
174
  # Manage temporary variables
146
175
  uid = MultitaskManager.get_thread_uid()
@@ -149,6 +178,8 @@ class VariableManager(DeleteableObject):
149
178
  self.__temporary_variables[uid].variable_names.add(var_name)
150
179
 
151
180
  def unregister_variable(self, variable_name, through_parent=False, delete_value=False):
181
+ self.__enter_variable_update_log_file()
182
+
152
183
  var_name = self.evaluate_variable_name(variable_name)
153
184
  if self.exists_variable(var_name, through_parent=False):
154
185
  value = self.__variables[var_name]
@@ -161,8 +192,8 @@ class VariableManager(DeleteableObject):
161
192
  except Exception:
162
193
  logger.exception(f"Catched exception while deleting object '{var_name}' (type: {Typing.get_object_class_fullname(value)})")
163
194
  else:
164
- if Tools.do_log(logger, logging.DEBUG):
165
- logger.debug(f"Deleted variable '{var_name}' (type: {Typing.get_object_class_fullname(value)})")
195
+ if Tools.do_log(self.__logger_update, logging.DEBUG):
196
+ self.__logger_update.debug(f"Deleted variable '{var_name}' (type: {Typing.get_object_class_fullname(value)})")
166
197
 
167
198
  del self.__variables[var_name]
168
199
  elif through_parent and self.parent:
@@ -270,6 +301,8 @@ class VariableManager(DeleteableObject):
270
301
  Tools.raise_same_exception_type(exc, f"{exc}\nVariable '{var_name}': {var_repr}", add_from=True)
271
302
 
272
303
  def exec_set_variable_expression(self, expression, value, through_parent=True, log_level=logging.INFO):
304
+ self.__enter_variable_update_log_file()
305
+
273
306
  var_name, expr_rest = self.__extract_expression_name(expression)
274
307
  var_value = self.get_variable_value(var_name, through_parent=through_parent)
275
308
  new_var_name = self.new_local_variable_name(sub_name=self.__regular_variable_name(var_name))
@@ -289,8 +322,8 @@ class VariableManager(DeleteableObject):
289
322
  # Tools.raise_same_exception_type(exc, f"{exc}\nVariable '{var_name}': {var_repr}", add_from=True)
290
323
  raise FunctionalException(f"Failed to set value in variable expression (by exec): {expression}=[{value}] (type: {Typing.get_object_class_fullname(value)})\nVariable '{var_name}': {var_repr}") from exc
291
324
  else:
292
- if Tools.do_log(logger, log_level):
293
- logger.log(log_level, f"Set value in variable expression (by exec): {expression}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
325
+ if Tools.do_log(self.__logger_update, log_level):
326
+ self.__logger_update.log(log_level, f"Set value in variable expression (by exec): {expression}=[{value}] (type: {Typing.get_object_class_fullname(value)})")
294
327
 
295
328
  def __regular_variable_name(self, name):
296
329
  return "".join([c if re.match(r'\w', c) else '_' for c in name])
@@ -73,7 +73,9 @@ class FeatureContext(Context):
73
73
  if not self.has_variable_manager():
74
74
  manager = VariableManager(SessionContext.instance().multitask_manager.get_thread_context().get_variable_manager())
75
75
  self.set_object("variable_manager", manager)
76
- manager.initialize(SessionContext.instance().dynamic_text_manager, SessionContext.instance().unique_value_manager)
76
+ file_path = SessionContext.instance().report_manager.current_feature_report.get_path("logs", "variable_update.log")
77
+ manager.initialize(SessionContext.instance().dynamic_text_manager, SessionContext.instance().unique_value_manager,
78
+ variable_update_log_file_path=file_path)
77
79
  return self.get_object("variable_manager")
78
80
 
79
81
 
@@ -135,7 +135,9 @@ class ScenarioContext(Context):
135
135
  if not self.has_variable_manager():
136
136
  manager = VariableManager(SessionContext.instance().get_feature_context().get_variable_manager())
137
137
  self.set_object("variable_manager", manager)
138
- manager.initialize(self.get_dynamic_text_manager(), SessionContext.instance().unique_value_manager)
138
+ file_path = SessionContext.instance().report_manager.current_scenario_report.get_path("logs", "variable_update.log")
139
+ manager.initialize(self.get_dynamic_text_manager(), SessionContext.instance().unique_value_manager,
140
+ variable_update_log_file_path=file_path)
139
141
  return self.get_object("variable_manager")
140
142
 
141
143
  def has_expression_evaluator(self):
@@ -26,7 +26,8 @@ import holado
26
26
  from holado_test.test_server.server.core.server_context import TestServerSessionContext
27
27
  holado.initialize(TSessionContext=TestServerSessionContext,
28
28
  logging_config_file_path=os.path.join(here, 'logging.conf'), log_level=logging.INFO,
29
- log_on_console=True, log_in_file=False,
29
+ log_on_console=True, log_in_file=False,
30
+ config_kwargs={'application_group':'test_server'},
30
31
  garbage_collector_periodicity=None)
31
32
 
32
33
  # Update stored campaigns
@@ -33,7 +33,9 @@ import holado
33
33
  # - log_on_console is True for initialization phase, it will be set to False when root log file will be defined
34
34
  # - logging config file
35
35
  from test_holado.test_holado_session_context import TestHoladoSessionContext
36
- holado.initialize(TSessionContext=TestHoladoSessionContext, logging_config_file_path=os.path.join(here, 'logging.conf'), log_level=logging.INFO, log_on_console=True)
36
+ holado.initialize(TSessionContext=TestHoladoSessionContext, logging_config_file_path=os.path.join(here, 'logging.conf'),
37
+ log_level=logging.INFO, log_on_console=True,
38
+ config_kwargs={'application_group':'test_runner'})
37
39
 
38
40
 
39
41
 
@@ -1,6 +1,6 @@
1
1
  @testing_solution
2
2
  @ais
3
- Feature: Test decode of AIS message from bitarry and its encode in NMEAv4
3
+ Feature: Test decode of AIS message from bitarray and its encode in NMEAv4
4
4
 
5
5
  @bitarray_to_nmea_through_decode
6
6
  Scenario Outline: from bitarray to NMEAv4 sentences through decode
@@ -0,0 +1,93 @@
1
+ @testing_solution
2
+ @ais
3
+ Feature: Test decode of NMEA AIS raw to dict
4
+
5
+ @nmea_to_dict_without_tagblock
6
+ Scenario: from NMEA raw to dict (without tagblock)
7
+ Given RAW = '!AIVDM,1,1,,A,13KG`rU0001RbwdT6CR3TB3f0000,0*4E'
8
+
9
+ When MSG_DICT = decode NMEA AIS raw RAW as dictionary
10
+
11
+ Then MSG_TABLE = convert dictionary MSG_DICT to name/value table
12
+ Then table MSG_TABLE is
13
+ | Name | Value |
14
+ | 'accuracy' | False |
15
+ | 'course' | 91.3 |
16
+ | 'heading' | 65 |
17
+ | 'lat' | 63.086733 |
18
+ | 'lon' | 21.555183 |
19
+ | 'maneuver' | 0 |
20
+ | 'mmsi' | 230025450 |
21
+ | 'msg_type' | 1 |
22
+ | 'radio' | 0 |
23
+ | 'raim' | False |
24
+ | 'repeat' | 0 |
25
+ | 'second' | 55 |
26
+ | 'speed' | 0.0 |
27
+ | 'status' | 5 |
28
+ | 'turn' | 0.0 |
29
+
30
+
31
+ @nmea_to_dict_with_tagblock
32
+ @without_merge
33
+ Scenario: from NMEA raw to dict (with tagblock, without merge)
34
+ Given RAW = '\\s:STATION1,t:Hello*2\\!AIVDM,1,1,,A,13KG`rU0001RbwdT6CR3TB3f0000,0*4E'
35
+
36
+ When TB_DICT, MSG_DICT = decode NMEA AIS raw RAW as dictionary
37
+
38
+ Then TB_TABLE = convert dictionary TB_DICT to name/value table
39
+ Then table TB_TABLE is
40
+ | Name | Value |
41
+ | 'source_station' | 'STATION1' |
42
+ | 'text' | 'Hello' |
43
+
44
+ Then MSG_TABLE = convert dictionary MSG_DICT to name/value table
45
+ Then table MSG_TABLE is
46
+ | Name | Value |
47
+ | 'accuracy' | False |
48
+ | 'course' | 91.3 |
49
+ | 'heading' | 65 |
50
+ | 'lat' | 63.086733 |
51
+ | 'lon' | 21.555183 |
52
+ | 'maneuver' | 0 |
53
+ | 'mmsi' | 230025450 |
54
+ | 'msg_type' | 1 |
55
+ | 'radio' | 0 |
56
+ | 'raim' | False |
57
+ | 'repeat' | 0 |
58
+ | 'second' | 55 |
59
+ | 'speed' | 0.0 |
60
+ | 'status' | 5 |
61
+ | 'turn' | 0.0 |
62
+
63
+
64
+ @nmea_to_dict_with_tagblock
65
+ @with_merge
66
+ Scenario: from NMEA raw to dict (with tagblock, with merge)
67
+ Given RAW = '\\s:STATION1,t:Hello*2\\!AIVDM,1,1,,A,13KG`rU0001RbwdT6CR3TB3f0000,0*4E'
68
+
69
+ When MSG_DICT = decode NMEA AIS raw RAW as dictionary (merge tag block and message dictionaries)
70
+
71
+ Then MSG_TABLE = convert dictionary MSG_DICT to name/value table
72
+ Then table MSG_TABLE is
73
+ | Name | Value |
74
+ | 'accuracy' | False |
75
+ | 'course' | 91.3 |
76
+ | 'heading' | 65 |
77
+ | 'lat' | 63.086733 |
78
+ | 'lon' | 21.555183 |
79
+ | 'maneuver' | 0 |
80
+ | 'mmsi' | 230025450 |
81
+ | 'msg_type' | 1 |
82
+ | 'radio' | 0 |
83
+ | 'raim' | False |
84
+ | 'repeat' | 0 |
85
+ | 'second' | 55 |
86
+ | 'source_station' | 'STATION1' |
87
+ | 'speed' | 0.0 |
88
+ | 'status' | 5 |
89
+ | 'text' | 'Hello' |
90
+ | 'turn' | 0.0 |
91
+
92
+
93
+
@@ -26,7 +26,7 @@ Feature: Message type 10 : Coordinated UTC Inquiry
26
26
  Then STRING_NMEA_MSG[-3] == 'A'
27
27
 
28
28
  # Decode NMEA message
29
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
29
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
30
30
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
31
31
  Then table DECODED_NMEA_MESSAGE_TABLE is
32
32
  | dest_mmsi | mmsi | msg_type | repeat |
@@ -26,7 +26,7 @@ Feature: Message type 12 : Addressed Safety Related Message
26
26
  Then STRING_NMEA_MSG[-3] == 'A'
27
27
 
28
28
  # Decode NMEA message
29
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
29
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
30
30
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
31
31
  Then table DECODED_NMEA_MESSAGE_TABLE is
32
32
  | dest_mmsi | mmsi | msg_type | repeat | retransmit | seqno | text |
@@ -26,7 +26,7 @@ Feature: Message type 14 : Safety Related Broadcast Message
26
26
  Then STRING_NMEA_MSG[-3] == 'A'
27
27
 
28
28
  # Decode NMEA message
29
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
29
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
30
30
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
31
31
  Then table DECODED_NMEA_MESSAGE_TABLE is
32
32
  | mmsi | msg_type | repeat | text |
@@ -26,7 +26,7 @@ Feature: Message type 15 : Interrogation
26
26
  Then STRING_NMEA_MSG[-3] == 'A'
27
27
 
28
28
  # Decode NMEA message
29
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
29
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
30
30
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
31
31
  Then table DECODED_NMEA_MESSAGE_TABLE is
32
32
  | mmsi | mmsi1 | mmsi2 | msg_type | offset1_1 | offset1_2 | offset2_1 | repeat | type1_1 | type1_2 | type2_1 |
@@ -26,7 +26,7 @@ Feature: Message type 16 : Assigned Mode Command
26
26
  Then STRING_NMEA_MSG[-3] == 'A'
27
27
 
28
28
  # Decode NMEA message
29
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
29
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
30
30
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
31
31
  Then table DECODED_NMEA_MESSAGE_TABLE is
32
32
  | increment1 | increment2 | mmsi | mmsi1 | mmsi2 | msg_type | offset1 | offset2 | repeat |
@@ -35,7 +35,7 @@ Feature: Message type 17 : GNSS Broadcast Binary Message
35
35
  Then STRING_NMEA_MSG[-3] == 'A'
36
36
 
37
37
  # Decode NMEA message
38
- Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionnary
38
+ Given DECODED_NMEA_MESSAGE = decode NMEA AIS message NMEA_SENTENCES as dictionary
39
39
  When DECODED_NMEA_MESSAGE_TABLE = convert dictionary DECODED_NMEA_MESSAGE to table with keys as columns
40
40
  Then table DECODED_NMEA_MESSAGE_TABLE is
41
41
  | data | lat | lon | mmsi | msg_type | repeat |