robotframework-qconnect-base 1.2.1__tar.gz → 1.2.2__tar.gz

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.
Files changed (28) hide show
  1. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/PKG-INFO +1 -1
  2. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/QConnectBase.pdf +0 -0
  3. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/connection_base.py +1 -1
  4. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/connection_manager.py +84 -57
  5. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/constants.py +4 -0
  6. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/qlogger.py +25 -13
  7. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/utils.py +8 -1
  8. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/version.py +2 -2
  9. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/robotframework_qconnect_base.egg-info/PKG-INFO +1 -1
  10. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/LICENSE +0 -0
  11. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/__init__.py +0 -0
  12. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/message/__init__.py +0 -0
  13. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/message/rabbitmq_client.py +0 -0
  14. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/serialclient/__init__.py +0 -0
  15. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/serialclient/serial_base.py +0 -0
  16. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/__init__.py +0 -0
  17. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/raw/__init__.py +0 -0
  18. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/raw/raw_tcp.py +0 -0
  19. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/ssh/__init__.py +0 -0
  20. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/ssh/ssh_client.py +0 -0
  21. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/QConnectBase/tcp/tcp_base.py +0 -0
  22. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/README.rst +0 -0
  23. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/robotframework_qconnect_base.egg-info/SOURCES.txt +0 -0
  24. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/robotframework_qconnect_base.egg-info/dependency_links.txt +0 -0
  25. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/robotframework_qconnect_base.egg-info/requires.txt +0 -0
  26. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/robotframework_qconnect_base.egg-info/top_level.txt +0 -0
  27. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/setup.cfg +0 -0
  28. {robotframework_qconnect_base-1.2.1 → robotframework_qconnect_base-1.2.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotframework-qconnect-base
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: Robot Framework test library for TCP, SSH, serial connection
5
5
  Home-page: https://github.com/test-fullautomation/robotframework-qconnect-base
6
6
  Author: Nguyen Huynh Tri Cuong
@@ -517,7 +517,7 @@ Suspend the control flow until a Trace message is received which matches to a sp
517
517
 
518
518
  * ``timeout``
519
519
 
520
- / *Condition*: optional / *Type*: int / *Default*: 0 /
520
+ / *Condition*: optional / *Type*: float / *Default*: 0 /
521
521
 
522
522
  Timeout parameter specified as a floating point number in the unit 'seconds'.
523
523
 
@@ -32,6 +32,7 @@ from robot.libraries.BuiltIn import BuiltIn
32
32
  from os.path import dirname
33
33
  from QConnectBase.utils import DictToClass
34
34
  from robot.api.deco import keyword
35
+ from robot.api.deco import library
35
36
  from robot.utils import timestr_to_secs
36
37
  import os
37
38
  import importlib
@@ -95,18 +96,16 @@ Class for storing parameters for verify action.
95
96
  element_def = {}
96
97
  args = None
97
98
 
98
-
99
+ @library(scope='GLOBAL', version=VERSION, auto_keywords=False, doc_format="reST")
99
100
  class ConnectionManager(Singleton):
100
101
  """
101
102
  Class to manage all connections.
102
103
  """
103
- ROBOT_LIBRARY_SCOPE = 'GLOBAL'
104
- ROBOT_AUTO_KEYWORDS = False
105
104
  LIBRARY_EXTENSION_PREFIX = 'robotframework_qconnect'
106
105
  LIBRARY_EXTENSION_PREFIX2 = 'QConnect'
106
+ MIN_VERIFY_TIMEOUT = 0.001
107
107
  DEFAULT_VERIFY_TIMEOUT = 5
108
108
  DEFAULT_EMERGENCY_TIMEOUT = 60 * 30
109
- ROBOT_LIBRARY_VERSION = VERSION
110
109
 
111
110
  id = 0
112
111
 
@@ -137,25 +136,7 @@ Constructor for ConnectionManager class.
137
136
  all_libs = [main_lib_path]
138
137
  all_libs.extend(extension_lib_paths)
139
138
  all_libs = list(set(all_libs))
140
- for path in all_libs:
141
- if path not in sys.path:
142
- sys.path.append(path)
143
- for module_loader, name, is_pkg in pkgutil.walk_packages(all_libs):
144
- # noinspection PyBroadException
145
- try:
146
- if not is_pkg and not name.startswith("setup"):
147
- importlib.import_module(name)
148
- else:
149
- # _module = module_loader.find_module(name).load_module(name)
150
- spec = importlib.util.find_spec(name)
151
- if spec and spec.loader:
152
- module = importlib.util.module_from_spec(spec)
153
- spec.loader.exec_module(module)
154
- else:
155
- print(f"⚠️ Could not load module: {name}")
156
- except Exception as _ex:
157
- pass
158
-
139
+ ConnectionManager.import_modules_from_paths(all_libs)
159
140
  supported_connection_classes_list = Utils.get_all_descendant_classes(ConnectionBase)
160
141
  self.supported_connection_classes_dict = {cls._CONNECTION_TYPE: cls for cls in supported_connection_classes_list}
161
142
 
@@ -164,6 +145,49 @@ Constructor for ConnectionManager class.
164
145
  self.ROBOT_LIBRARY_LISTENER = self
165
146
  self.ROBOT_LISTENER_API_VERSION = 3
166
147
 
148
+ @staticmethod
149
+ def import_modules_from_paths(paths):
150
+ """
151
+ Import all modules from given paths.
152
+
153
+ **Arguments:**
154
+
155
+ * ``paths``
156
+
157
+ / *Condition*: required / *Type*: list /
158
+
159
+ List of paths to import modules from.
160
+ """
161
+ for path in paths:
162
+ for prefix in [ConnectionManager.LIBRARY_EXTENSION_PREFIX, ConnectionManager.LIBRARY_EXTENSION_PREFIX2]:
163
+ if prefix in path:
164
+ if os.path.isdir(path):
165
+ for root, dirs, files in os.walk(path):
166
+ for file in files:
167
+ if file.endswith('.py'):
168
+ module_path = os.path.join(root, file)
169
+ module_name = os.path.splitext(os.path.relpath(module_path, os.path.dirname(path)))[0].replace(
170
+ os.sep, '.')
171
+ if module_name not in sys.modules:
172
+ spec = importlib.util.spec_from_file_location(module_name, module_path)
173
+ if spec and spec.loader:
174
+ module = importlib.util.module_from_spec(spec)
175
+ sys.modules[module_name] = module
176
+ try:
177
+ spec.loader.exec_module(module)
178
+ except Exception as _ex:
179
+ pass
180
+ elif os.path.isfile(path) and path.endswith('.py'):
181
+ module_name = os.path.splitext(os.path.basename(path))[0]
182
+ if module_name not in sys.modules:
183
+ spec = importlib.util.spec_from_file_location(module_name, path)
184
+ if spec and spec.loader:
185
+ module = importlib.util.module_from_spec(spec)
186
+ sys.modules[module_name] = module
187
+ try:
188
+ spec.loader.exec_module(module)
189
+ except Exception as _ex:
190
+ pass
167
191
 
168
192
  def __del__(self):
169
193
  """
@@ -234,8 +258,7 @@ Remove a connection by name.
234
258
  if conn_name in self.connection_manage_dict.keys():
235
259
  del self.connection_manage_dict[conn_name]
236
260
 
237
-
238
- def get_connection_by_name(self, conn_name):
261
+ def get_connection_by_name(self, conn_name, raise_exception=False):
239
262
  """
240
263
  Get an exist connection by name.
241
264
 
@@ -247,6 +270,12 @@ Get an exist connection by name.
247
270
 
248
271
  Connection's name.
249
272
 
273
+ * ``raise_exception``
274
+
275
+ / *Condition*: optional / *Type*: bool /
276
+
277
+ If True, raise exception when connection is not found.
278
+
250
279
  **Returns:**
251
280
 
252
281
  * ``conn``
@@ -258,6 +287,10 @@ Get an exist connection by name.
258
287
  conn = None
259
288
  if conn_name in self.connection_manage_dict.keys():
260
289
  conn = self.connection_manage_dict[conn_name]
290
+
291
+ if raise_exception and conn is None:
292
+ raise Exception(constants.String.CONNECTION_NOT_CONNECTED % conn_name)
293
+
261
294
  return conn
262
295
 
263
296
  @keyword
@@ -306,13 +339,11 @@ Making a connection.
306
339
 
307
340
  Example ``conn_conf`` for ``TCPIPClient``:
308
341
 
309
- ```
310
- {
311
- "conn_type": "TCPIPClient",
312
- "address": [server host], # Optional. Default value is "localhost".
313
- "port": [server port] # Optional. Default value is 1234.
314
- }
315
- ```
342
+ | {
343
+ | "conn_type": "TCPIPClient",
344
+ | "address": [server host], # Optional. Default value is "localhost".
345
+ | "port": [server port] # Optional. Default value is 1234.
346
+ | }
316
347
 
317
348
  * ``conn_type`` (deprecated)
318
349
 
@@ -321,6 +352,7 @@ Making a connection.
321
352
  Type of connection. It can be specified in ``conn_conf`` dictionary.
322
353
 
323
354
  Supported connection types:
355
+
324
356
  - ``TCPIPClient``: Create a Raw TCP/IP connection to TCP Server.
325
357
  - ``SSHClient``: Create a client connection to a SSH server.
326
358
  - ``SerialClient``: Create a client connection via Serial Port.
@@ -429,9 +461,7 @@ Send command to a connection.
429
461
 
430
462
  (*no returns*)
431
463
  """
432
- if conn_name not in self.connection_manage_dict.keys():
433
- raise AssertionError("The '%s' connection hasn't been established. Please connect first." % conn_name)
434
- connection_obj = self.connection_manage_dict[conn_name]
464
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
435
465
  try:
436
466
  connection_obj.send_obj(command, **kwargs)
437
467
  BuiltIn().log(f"command '{command}' is sent to '{conn_name}'", constants.LOG_LEVEL_INFO)
@@ -478,13 +508,11 @@ Transfer file from local to remote and vice versa.
478
508
 
479
509
  (*no returns*)
480
510
  """
481
- if conn_name not in self.connection_manage_dict.keys():
482
- raise AssertionError(f"The '{conn_name}' connection hasn't been established. Please connect first.")
483
- connection_obj = self.connection_manage_dict[conn_name]
511
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
484
512
  try:
485
513
  connection_obj.transfer_file(src, dest, type)
486
514
  except AttributeError:
487
- raise Exception(f"'{connection_obj._CONNECTION_TYPE}' connection type has not been supported for transferring file.") from None
515
+ raise Exception(constants.String.CONNECTION_UNSUPPORTED_KEYWORD % (connection_obj._CONNECTION_TYPE, "file transfer")) from None
488
516
  except Exception as ex:
489
517
  raise Exception(f"Unable to transfer file to '{conn_name}' connection. Exception: '{ex}'") from None
490
518
 
@@ -527,17 +555,14 @@ Transfer item from local to remote and vice versa.
527
555
 
528
556
  (*no returns*)
529
557
  """
530
- if conn_name not in self.connection_manage_dict.keys():
531
- raise AssertionError(f"The '{conn_name}' connection hasn't been established. Please connect first.")
532
- connection_obj = self.connection_manage_dict[conn_name]
558
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
533
559
  try:
534
560
  connection_obj.transfer_item(src, dest, type)
535
561
  except AttributeError:
536
- raise Exception(f"'{connection_obj._CONNECTION_TYPE}' connection type has not been supported for transferring item.") from None
562
+ raise Exception(constants.String.CONNECTION_UNSUPPORTED_KEYWORD % (connection_obj._CONNECTION_TYPE, "item transfer")) from None
537
563
  except Exception as ex:
538
564
  raise Exception(f"Unable to transfer item to '{conn_name}' connection. Exception: '{ex}'") from None
539
565
 
540
-
541
566
  @keyword
542
567
  def execute_script(self, conn_name, script_path):
543
568
  """
@@ -561,14 +586,12 @@ Executes a script file by sending commands to a device through the provided conn
561
586
 
562
587
  (*no returns*)
563
588
  """
564
- if conn_name not in self.connection_manage_dict.keys():
565
- raise AssertionError("The '%s' connection hasn't been established. Please connect first." % conn_name)
566
- connection_obj = self.connection_manage_dict[conn_name]
589
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
567
590
  try:
568
591
  connection_obj.execute_script(script_path)
569
592
  except AttributeError as attrErr:
570
593
  test = inspect.getfile(connection_obj.__class__)
571
- raise Exception("'%s' connection type has not been supported for execute script." % connection_obj._CONNECTION_TYPE) from None
594
+ raise Exception(constants.String.CONNECTION_UNSUPPORTED_KEYWORD % (connection_obj._CONNECTION_TYPE, "script execution")) from None
572
595
  except Exception as ex:
573
596
  raise Exception("Unable to execute script path '%s'. Exception: %s" % (script_path, str(ex))) from None
574
597
 
@@ -578,6 +601,7 @@ Executes a script file by sending commands to a device through the provided conn
578
601
  Set the default verify timeout value for the connection.
579
602
 
580
603
  Supports flexible input formats such as:
604
+
581
605
  - Duration with units (e.g. '1h 10s', '2m30s', '500ms')
582
606
  - HH:MM:SS format (e.g. '01:00:10' for 1 hour, 0 minutes, 10 seconds)
583
607
  - Plain numeric values (e.g. '42') interpreted as seconds
@@ -593,6 +617,7 @@ Supports flexible input formats such as:
593
617
  - ``m`` for minutes (or ``ms`` for milliseconds)
594
618
  - ``s`` for seconds
595
619
  - ``ms`` for milliseconds
620
+
596
621
  If no unit is specified, the value is interpreted as seconds.
597
622
  """
598
623
  time_second = timestr_to_secs(time_out)
@@ -621,6 +646,7 @@ Supports flexible input formats such as:
621
646
  - ``m`` for minutes (or ``ms`` for milliseconds)
622
647
  - ``s`` for seconds
623
648
  - ``ms`` for milliseconds
649
+
624
650
  If no unit is specified, the value is interpreted as seconds.
625
651
  """
626
652
  time_second = timestr_to_secs(time_out)
@@ -648,6 +674,7 @@ Verify a pattern from connection response after sending a command.
648
674
  Expectation expressed as a **regular expression pattern** (more robust than a plain string comparison).
649
675
 
650
676
  It will match:
677
+
651
678
  - a single line by default (``fetch_block`` not used)
652
679
  - multiple lines if ``fetch_block`` is enabled
653
680
 
@@ -725,14 +752,17 @@ Verify a pattern from connection response after sending a command.
725
752
  then the returned list will be ``['1st', 'command']``.
726
753
 
727
754
  Thus:
728
- - ``${res}[0]`` will be **1st**,
729
- i.e. the first *captured string* defined in the pattern ``([0-9]..)``.
730
755
 
731
- - ``${res}[1]`` will be **command**,
732
- i.e. the second *captured string* defined in the pattern ``(command)``.
756
+ - ``${res}[0]`` will be **1st**, i.e. the first *captured string* defined in the pattern ``([0-9]..)``.
757
+ - ``${res}[1]`` will be **command**, i.e. the second *captured string* defined in the pattern ``(command)``.
733
758
 
734
759
  """
735
760
  validate_regex_pattern(search_pattern, 'search_pattern')
761
+ if timeout is not None and timeout < self.MIN_VERIFY_TIMEOUT:
762
+ raise Exception(
763
+ f"Timeout value '{timeout}' is too small. "
764
+ f"Please enter a value of {self.MIN_VERIFY_TIMEOUT} seconds or higher."
765
+ )
736
766
  # Parameter validation: eob_pattern and filter_pattern are only valid when fetch_block is True
737
767
  if not fetch_block:
738
768
  if eob_pattern != None:
@@ -747,16 +777,13 @@ Verify a pattern from connection response after sending a command.
747
777
  if filter_pattern and has_capturing_groups(filter_pattern, 'filter_pattern'):
748
778
  BuiltIn().log(f"Warning: Capturing groups are not supported within the filter_pattern '{filter_pattern}'.", constants.LOG_LEVEL_WARNING)
749
779
 
750
- if conn_name not in self.connection_manage_dict.keys():
751
- raise AssertionError("The '%s' connection hasn't been established. Please connect first." % conn_name)
752
-
753
780
  # if search_pattern is None:
754
781
  # raise Exception("The 'search_pattern' have to be a regex string instead of None.")
755
782
 
756
783
  if send_cmd is None:
757
784
  send_cmd = ''
758
785
 
759
- connection_obj = self.connection_manage_dict[conn_name]
786
+ connection_obj = self.get_connection_by_name(conn_name, raise_exception=True)
760
787
  if connection_obj.get_connection_type() in ["DLT", "DLTConnector", "TTFisclient"]:
761
788
  match_try = 5
762
789
 
@@ -769,7 +796,7 @@ Verify a pattern from connection response after sending a command.
769
796
  res = None
770
797
  for i in range(1, match_try+1):
771
798
  kwargs['send_cmd'] = send_cmd
772
- res = connection_obj.wait_4_trace(search_pattern, int(timeout), fetch_block, eob_pattern, filter_pattern, **kwargs)
799
+ res = connection_obj.wait_4_trace(search_pattern, timeout, fetch_block, eob_pattern, filter_pattern, **kwargs)
773
800
  if res is None:
774
801
  log_level = constants.LOG_LEVEL_WARNING if (i == match_try) else constants.LOG_LEVEL_INFO
775
802
  BuiltIn().log(f"[{conn_name}] Match try {i}/{match_try} timed out ('{search_pattern}')", log_level)
@@ -38,6 +38,8 @@ LOG_LEVEL_DEBUG = 'DEBUG'
38
38
  LOG_LEVEL_ERROR = 'ERROR'
39
39
  LOG_LEVEL_WARNING = 'WARN'
40
40
 
41
+ DEFAULT_LOGGER = "DEFAULT_FILE"
42
+
41
43
  LOG_FORMATTER = "%(asctime)s [%(threadName)-.128s] [%(levelname)-5.5s] %(message)s"
42
44
  platform_ = platform.system().lower()
43
45
  if platform_.startswith(OS_WINDOWS_STR):
@@ -65,3 +67,5 @@ class String:
65
67
  CONNECTION_TYPE_CONFUSED = "Mismatch: 'conn_type' (%s) and 'con_conf[\"conn_type\"]' (%s) both set but differ. Expected: set in only one or identical in both."
66
68
  CONNECTION_MODE_CONFUSED = "Mismatch: 'conn_mode' (%s) and 'con_conf[\"conn_mode\"]' (%s) both set but differ. Expected: set in only one or identical in both."
67
69
  CONNECTION_BROKEN = "Connection has been broken while trying to match the pattern."
70
+ CONNECTION_UNSUPPORTED_KEYWORD = "'%s' connection type is not supported for %s."
71
+ CONNECTION_NOT_CONNECTED = "The '%s' connection hasn't been established. Please connect first."
@@ -31,6 +31,7 @@ from QConnectBase.utils import *
31
31
  import QConnectBase.constants as constants
32
32
  import logging
33
33
  import os
34
+ import sys
34
35
 
35
36
 
36
37
  class ColorFormatter(logging.Formatter):
@@ -104,7 +105,7 @@ Constructor for QFileHandler class.
104
105
  Log's formatter.
105
106
  """
106
107
  path = self.get_log_path(config)
107
- super(QFileHandler, self).__init__(path)
108
+ super(QFileHandler, self).__init__(path, mode='w')
108
109
  self.setFormatter(formatter)
109
110
 
110
111
  @staticmethod
@@ -126,13 +127,17 @@ Get the log file path for this handler.
126
127
 
127
128
  Log file path.
128
129
  """
129
- out_dir = BuiltIn()._context.output._settings.output_directory
130
+ try:
131
+ out_dir = BuiltIn()._context.output._settings.output_directory
132
+ except Exception:
133
+ out_dir = os.getcwd()
134
+
130
135
  dir_log = os.path.dirname(config.logfile)
131
136
  if not os.path.isabs(dir_log):
132
- dir_log = out_dir + '/' + dir_log
137
+ dir_log = os.path.join(out_dir, dir_log)
133
138
  if not os.path.exists(dir_log):
134
139
  os.makedirs(dir_log)
135
- return "{0}/{1}".format(dir_log, os.path.basename(config.logfile))
140
+ return os.path.join(dir_log, os.path.basename(config.logfile))
136
141
 
137
142
  @staticmethod
138
143
  def get_config_supported(config):
@@ -155,7 +160,10 @@ Check if the connection config is supported by this handler.
155
160
 
156
161
  False if the config is not supported.
157
162
  """
158
- return config.logfile is not None and config.logfile != 'nonlog' and config.logfile != 'console'
163
+ return isinstance(config.logfile, str) and \
164
+ config.logfile != 'nonlog' and \
165
+ config.logfile != 'console' and \
166
+ config.logfile != constants.DEFAULT_LOGGER
159
167
 
160
168
 
161
169
  class QDefaultFileHandler(logging.FileHandler):
@@ -214,8 +222,11 @@ Get the log file path for this handler.
214
222
 
215
223
  Log file path.
216
224
  """
217
- out_dir = BuiltIn()._context.output._settings.output_directory
218
- return "{0}/{1}.log".format(out_dir, logger_name + "_trace")
225
+ try:
226
+ out_dir = BuiltIn()._context.output._settings.output_directory
227
+ except Exception:
228
+ out_dir = os.getcwd()
229
+ return os.path.join(out_dir, logger_name + "_trace.log")
219
230
 
220
231
  @staticmethod
221
232
  def get_config_supported(config):
@@ -238,7 +249,8 @@ Check if the connection config is supported by this handler.
238
249
 
239
250
  False if the config is not supported.
240
251
  """
241
- return config.logfile is None
252
+ return (isinstance(config.logfile, bool) and config.logfile) or \
253
+ config.logfile == constants.DEFAULT_LOGGER
242
254
 
243
255
 
244
256
  class QConsoleHandler(logging.StreamHandler):
@@ -247,7 +259,7 @@ Handler class for console log.
247
259
  """
248
260
  def __init__(self, _config, _logger_name, _formatter):
249
261
  """
250
- Constructor for QDefaultFileHandler class.
262
+ Constructor for QConsoleHandler class.
251
263
 
252
264
  **Arguments:**
253
265
 
@@ -273,7 +285,7 @@ Constructor for QDefaultFileHandler class.
273
285
 
274
286
  (*no returns*)
275
287
  """
276
- super(QConsoleHandler, self).__init__()
288
+ super(QConsoleHandler, self).__init__(sys.__stdout__)
277
289
  self.setFormatter(ColorFormatter())
278
290
 
279
291
  @staticmethod
@@ -370,11 +382,11 @@ Set handler for logger.
370
382
  for handler in supported_handler_classes_list:
371
383
  # noinspection PyBroadException
372
384
  try:
373
- if handler.get_config_supported(config):
385
+ if hasattr(handler, 'get_config_supported') and handler.get_config_supported(config):
374
386
  handler_ins = handler(config, self.logger_name, self.formatter)
375
387
  handler_ins.setLevel(log_level)
376
388
  self.logger.addHandler(handler_ins)
377
389
  return handler_ins
378
- except:
379
- pass
390
+ except Exception as reason:
391
+ raise Exception(f"Failed to initialize logger for '{config.logfile}'. Reason: {reason}.") from None
380
392
  return None
@@ -67,7 +67,7 @@ class DictToClass:
67
67
  Class for converting dictionary to class object.
68
68
  """
69
69
  exclude_list = []
70
- logfile = None
70
+ logfile = constants.DEFAULT_LOGGER
71
71
  encoding = 'utf-8'
72
72
 
73
73
  def __init__(self, **dictionary):
@@ -86,6 +86,13 @@ Class for converting dictionary to class object.
86
86
  self.__dict__[k] = v
87
87
  except Exception as ex:
88
88
  raise Exception(f"The configuration 'conn_conf' is invalid. Details: {ex}") from None
89
+
90
+ if not isinstance(self.logfile, (bool, str)) and self.logfile is not None:
91
+ raise TypeError(
92
+ f"The configuration parameter 'logfile' inside 'conn_conf' must be of type bool, str, or None. "
93
+ f"Received type: {type(self.logfile).__name__} with value: {self.logfile!r}."
94
+ )
95
+
89
96
  self.validate()
90
97
 
91
98
  def validate(self):
@@ -12,5 +12,5 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- VERSION = '1.2.1'
16
- VERSION_DATE = '06.11.2025'
15
+ VERSION = '1.2.2'
16
+ VERSION_DATE = '25.11.2025'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotframework-qconnect-base
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: Robot Framework test library for TCP, SSH, serial connection
5
5
  Home-page: https://github.com/test-fullautomation/robotframework-qconnect-base
6
6
  Author: Nguyen Huynh Tri Cuong