holado 0.2.4__py3-none-any.whl → 0.2.6__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 (49) hide show
  1. holado/__init__.py +62 -26
  2. holado/common/context/service_manager.py +10 -2
  3. holado/common/context/session_context.py +43 -12
  4. holado/common/handlers/object.py +14 -5
  5. holado/common/handlers/undefined.py +16 -6
  6. holado/holado_config.py +1 -0
  7. {holado-0.2.4.dist-info → holado-0.2.6.dist-info}/METADATA +1 -1
  8. {holado-0.2.4.dist-info → holado-0.2.6.dist-info}/RECORD +49 -48
  9. holado_core/common/block/scope_steps.py +2 -2
  10. holado_core/common/resource/persisted_method_to_call_manager.py +2 -2
  11. holado_core/common/tools/path_manager.py +8 -4
  12. holado_core/common/tools/tools.py +24 -7
  13. holado_grpc/api/rpc/grpc_client.py +122 -118
  14. holado_helper/docker/logging.conf +3 -1
  15. holado_helper/docker/run_holado_test_nonreg_in_docker.sh +28 -28
  16. holado_helper/docker/run_terminal_in_docker-with_docker_control.sh +27 -27
  17. holado_helper/docker/run_terminal_in_docker.sh +26 -26
  18. holado_helper/initialize_holado.py +72 -0
  19. holado_helper/script/action.py +21 -9
  20. holado_helper/script/initialize_script.py +8 -28
  21. holado_helper/script/script.py +2 -2
  22. holado_logging/__init__.py +5 -8
  23. holado_logging/common/logging/holado_logger.py +2 -2
  24. holado_logging/common/logging/log_config.py +43 -18
  25. holado_logging/common/logging/log_manager.py +20 -19
  26. holado_multitask/multitasking/multitask_manager.py +1 -1
  27. holado_multitask/multithreading/thread.py +8 -4
  28. holado_protobuf/ipc/protobuf/protobuf_messages.py +1 -1
  29. holado_scripting/common/tools/evaluate_parameters.py +23 -5
  30. holado_scripting/common/tools/expression_evaluator.py +115 -113
  31. holado_scripting/tests/behave/steps/scenario/if_steps.py +2 -2
  32. holado_scripting/text/interpreter/functions/function_hex_to_bytes.py +1 -1
  33. holado_scripting/text/interpreter/text_interpreter.py +20 -21
  34. holado_test/behave/behave_environment.py +31 -12
  35. holado_test/behave/independant_runner.py +3 -5
  36. holado_test/scenario/step_tools.py +13 -12
  37. holado_test/scenario/tester_tools.py +3 -1
  38. holado_value/common/tables/comparators/table_2_value_table_cell_comparator.py +1 -1
  39. holado_value/common/tables/converters/value_table_converter.py +1 -1
  40. holado_value/common/tables/value_table_cell.py +5 -1
  41. holado_value/common/tools/value.py +56 -33
  42. holado_value/common/tools/value_types.py +6 -0
  43. test_holado/environment.py +1 -1
  44. test_holado/features/NonReg/{ipc → holado_binary}/bit_series.feature +13 -0
  45. test_holado/features/NonReg/test_steps/common.feature +1 -1
  46. test_holado/logging.conf +3 -1
  47. {holado-0.2.4.dist-info → holado-0.2.6.dist-info}/WHEEL +0 -0
  48. {holado-0.2.4.dist-info → holado-0.2.6.dist-info}/licenses/LICENSE +0 -0
  49. /test_holado/features/NonReg/{ipc → holado_binary}/bit_series.error.feature +0 -0
@@ -0,0 +1,72 @@
1
+
2
+ #################################################
3
+ # HolAdo (Holistic Automation do)
4
+ #
5
+ # (C) Copyright 2021-2025 by Eric Klumpp
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+ # The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
12
+ #################################################
13
+
14
+
15
+ #################################################
16
+ # GOAL: Tools when using a clone of HolAdo project.
17
+ #
18
+ # This file contains methods usefull to initialize environments using a clone of HolAdo project.
19
+ #
20
+ # USAGE:
21
+ # - Copy this file in projects using HolAdo.
22
+ # - Define environment variable HOLADO_PATH with path to cloned HolAdo project.
23
+ # If HOLADO_PATH is defined, sources of cloned HolAdo project are used, else installed holado package is used.
24
+ #################################################
25
+
26
+
27
+
28
+ import os
29
+ import sys
30
+
31
+
32
+ def insert_sys_path(path, index=0):
33
+ """Insert a path in sys.path if it doesn't already exists.
34
+ """
35
+ if path not in sys.path:
36
+ sys.path.insert(index, path)
37
+
38
+ def insert_sys_paths(list_paths, index=0):
39
+ """Insert a list of path in sys.path if it doesn't already exists.
40
+ """
41
+ if list_paths:
42
+ for path in list_paths:
43
+ insert_sys_path(path, index=index)
44
+
45
+ def insert_holado_source_paths(with_test_behave=True):
46
+ """Insert in sys.path all HolAdo source paths.
47
+ If environment variable HOLADO_PATH is defined with path to HolAdo project, following paths are inserted in sys.path:
48
+ - HOLADO_PATH/src: path to holado modules sources
49
+ - HOLADO_PATH/tests/behave (if with_test_behave==True): path to holado test sources, needed by testing solutions
50
+ """
51
+ holado_path = os.getenv('HOLADO_PATH')
52
+ if holado_path is None:
53
+ try:
54
+ import holado # @UnusedImport
55
+ except Exception as exc:
56
+ if "No module named" in str(exc):
57
+ raise Exception(f"If environment variable HOLADO_PATH is not defined with path to HolAdo project, 'holado' python package must be installed")
58
+ else:
59
+ raise exc
60
+ else:
61
+ # holado is installed, and all sources are already accessible
62
+ pass
63
+ else:
64
+ print(f"Using HolAdo project installed in '{holado_path}'")
65
+ # import traceback
66
+ # print("".join(traceback.format_list(traceback.extract_stack())))
67
+ # insert_sys_path(holado_path)
68
+ insert_sys_path(os.path.join(holado_path, "src"))
69
+ if with_test_behave:
70
+ insert_sys_path(os.path.join(holado_path, "tests", "behave"))
71
+
72
+
@@ -19,6 +19,7 @@ from holado_core.common.tools.tools import Tools
19
19
  from holado_core.common.actors.actions import Action
20
20
  from holado_core.common.exceptions.technical_exception import TechnicalException
21
21
  from holado_python.standard_library.typing import Typing
22
+ from holado.common.handlers.undefined import not_applicable
22
23
 
23
24
  logger = logging.getLogger(__name__)
24
25
 
@@ -80,22 +81,33 @@ class BehaveActionRunner():
80
81
  self.__action = FeaturesBehaveAction(action_info.behave_args, variable_manager)
81
82
  self.__action_info = action_info
82
83
 
84
+ def __compute_variable_values(self):
85
+ res = {}
86
+ self.__add_variable_values(res, self.__action_info.static_params)
87
+ self.__add_variable_values(res, self.__action_info.params)
88
+ return res
89
+
90
+ def __add_variable_values(self, res, params):
91
+ if params:
92
+ for key, value in params.items():
93
+ if key == 'STATUS':
94
+ continue
95
+ if value is not_applicable:
96
+ res[key] = 'N/A'
97
+ else:
98
+ res[key] = value
99
+
83
100
  def run(self):
84
101
  logger.info(f"Processing action '{self.__action_info.action}' of index {self.__action_info.index}: {self.__action_info.params}")
85
102
  if Tools.do_log(logger, logging.DEBUG):
86
103
  logger.debug(f"Running behave with arguments '{self.__action_info.behave_args}' on action of index {self.__action_info.index}: {self.__action_info.params}")
87
104
 
88
- variable_values = {}
89
- if self.__action_info.static_params:
90
- for key, value in self.__action_info.static_params.items():
91
- variable_values[key] = value
92
- if self.__action_info.params:
93
- for key, value in self.__action_info.params.items():
94
- if key == 'STATUS':
95
- continue
96
- variable_values[key] = value
105
+ variable_values = self.__compute_variable_values()
97
106
 
98
107
  logger.info(f"Launching behave with arguments: {self.__action_info.behave_args}")
108
+ if Tools.do_log(logger, logging.DEBUG):
109
+ if variable_values:
110
+ logger.debug(f" and with variables:\n{Tools.represent_object(variable_values, 8)}")
99
111
  res = self.__action.execute(variable_values)
100
112
  logger.info(f"behave finished with result: {res}")
101
113
 
@@ -16,9 +16,9 @@
16
16
  # Usually, it is copied and adapted for specific usage.
17
17
 
18
18
  import os
19
- import sys
20
19
  import logging
21
20
  import argparse
21
+ from holado_helper.initialize_holado import insert_sys_path, insert_sys_paths
22
22
 
23
23
 
24
24
  def _chdir(path):
@@ -26,32 +26,12 @@ def _chdir(path):
26
26
  os.chdir(path)
27
27
  return res
28
28
 
29
- def __insert_sys_path(path):
30
- if path not in sys.path:
31
- sys.path.insert(0, path)
32
-
33
- def _insert_sys_paths(additional_sys_paths=None):
34
- # Insert additional paths
35
- if additional_sys_paths is not None:
36
- for sp in additional_sys_paths:
37
- __insert_sys_path(sp)
38
-
39
- # Insert Holado paths
40
- holado_path = os.getenv('HOLADO_PATH')
41
- if holado_path is None:
42
- # If HolAdo sources are not cloned on this environment, use path within this installation
43
- from holado import get_holado_path
44
- holado_path = get_holado_path()
45
- __insert_sys_path(os.path.join(holado_path) )
46
- __insert_sys_path(os.path.join(holado_path, "src") )
47
- __insert_sys_path(os.path.join(holado_path, "tests", "behave") )
48
-
49
- def _initialize_holado(TSessionContext=None, logging_config_file=None, log_level=logging.WARNING, log_in_file=False, with_session_path=False, **kwargs):
29
+ def _initialize_holado(TSessionContext=None, logging_config_file_path=None, log_level=logging.WARNING, log_in_file=False, with_session_path=False, **kwargs):
50
30
  import holado
51
31
  session_kwargs={'with_session_path':with_session_path or log_in_file}
52
32
  if kwargs:
53
33
  session_kwargs.update(kwargs)
54
- holado.initialize_for_script(TSessionContext=TSessionContext, logging_config_file=logging_config_file,
34
+ holado.initialize_for_script(TSessionContext=TSessionContext, logging_config_file_path=logging_config_file_path,
55
35
  log_level=log_level, log_in_file=log_in_file, log_on_console=not log_in_file,
56
36
  session_kwargs=session_kwargs)
57
37
 
@@ -67,24 +47,24 @@ def initialize(work_dir_path=None, change_work_dir=True,
67
47
 
68
48
  if additional_sys_paths:
69
49
  sys_paths.extend(additional_sys_paths)
70
- _insert_sys_paths(sys_paths)
50
+ insert_sys_paths(sys_paths)
71
51
 
72
- logging_config_file=None
52
+ logging_config_file_path=None
73
53
  for dir_path in [res, work_dir_path, os.getcwd()]:
74
54
  if dir_path is not None:
75
55
  file_path = os.path.join(dir_path, "logging.conf")
76
56
  if os.path.exists(file_path):
77
- logging_config_file = file_path
57
+ logging_config_file_path = file_path
78
58
  break
79
59
 
80
- _initialize_holado(TSessionContext, logging_config_file, log_level, log_in_file, with_session_path)
60
+ _initialize_holado(TSessionContext, logging_config_file_path, log_level, log_in_file, with_session_path)
81
61
 
82
62
  return res
83
63
 
84
64
  def change_working_dir(work_dir_path=None):
85
65
  if work_dir_path:
86
66
  res = _chdir(work_dir_path)
87
- __insert_sys_path(work_dir_path)
67
+ insert_sys_path(work_dir_path)
88
68
  return res
89
69
  else:
90
70
  return None
@@ -76,7 +76,7 @@ class Script(object):
76
76
  return parser
77
77
 
78
78
  def change_working_dir(self, work_dir_path):
79
- from initialize_script import change_working_dir as init_cd # @UnresolvedImport
79
+ from holado_helper.script.initialize_script import change_working_dir as init_cd # @UnresolvedImport
80
80
 
81
81
  # If user working dir is not yet defined, save current working dir as user working dir
82
82
  if self.__user_work_dir is None:
@@ -90,7 +90,7 @@ class Script(object):
90
90
 
91
91
  def initialize(self):
92
92
  if self.args is not None and hasattr(self.args, 'log_level') and hasattr(self.args, 'log_in_file'):
93
- from initialize_script import change_logging_config # @UnresolvedImport
93
+ from holado_helper.script.initialize_script import change_logging_config # @UnresolvedImport
94
94
  change_logging_config(log_level=self.args.log_level, log_in_file=self.args.log_in_file)
95
95
 
96
96
  def run(self):
@@ -14,23 +14,20 @@
14
14
 
15
15
 
16
16
 
17
- def configure(initialize_logging=True, log_level=None):
17
+ def configure(use_holado_logger=True, logging_config_file_path=None, log_level=None, log_on_console=False, log_in_file=True):
18
18
  from holado_logging.common.logging.log_config import LogConfig
19
- if log_level is None:
20
- import logging
21
- log_level = logging.INFO
22
-
23
- LogConfig.configure(initialize_logging=initialize_logging, log_level=log_level)
19
+ LogConfig.configure(use_holado_logger=use_holado_logger, config_file_path=logging_config_file_path, log_level=log_level, log_on_console=log_on_console, log_in_file=log_in_file)
24
20
 
25
21
  def dependencies():
26
22
  return None
27
23
 
28
- def register():
24
+ def initialize_and_register():
29
25
  from holado.common.context.session_context import SessionContext
30
26
  from holado_logging.common.logging.log_manager import LogManager
31
27
 
32
28
  log_manager = LogManager()
33
- log_manager.initialize(log_on_console=True)
29
+ log_manager.configure()
30
+ log_manager.initialize()
34
31
 
35
32
  SessionContext.instance().services.register_service_instance("log_manager", log_manager, SessionContext.instance(),
36
33
  raise_if_service_exist=False, raise_if_object_exist=False)
@@ -15,7 +15,7 @@ import logging
15
15
 
16
16
  logger = logging.getLogger(__name__)
17
17
 
18
- #TODO EKL: rename HoladoLogger
18
+
19
19
  class HALogger(logging.Logger):
20
20
  default_message_size_limit = None
21
21
 
@@ -56,7 +56,7 @@ class HALogger(logging.Logger):
56
56
  # logger.print(f"Change logger {self} level to {level}")
57
57
  # logging.Logger.setLevel(self, level)
58
58
 
59
- class TestRootLogger(HALogger):
59
+ class HARootLogger(HALogger):
60
60
  """
61
61
  Implementation is a copy of logging.RootLogger
62
62
  """
@@ -20,36 +20,61 @@ import logging
20
20
  class LogConfig(object):
21
21
  TLogger = None
22
22
  TManager = None
23
+ config_file_path = None
23
24
  default_level = logging.INFO
25
+ log_on_console=False
26
+ log_in_file=True
27
+ __is_configured = False
24
28
 
25
29
  @classmethod
26
- def configure(cls, initialize_logging=True, log_level=None):
30
+ def configure(cls, use_holado_logger=True, config_file_path=None, log_level=None, log_on_console=False, log_in_file=True):
31
+ if cls.__is_configured:
32
+ logging.warning(f"Logging was already configured, it is not possible to configure it twice. This new configuration is skipped.")
33
+ return
34
+
27
35
  # HolAdo needs at least to add logging level TRACE and PRINT
28
36
  cls.add_logging_level_trace()
29
37
  cls.add_logging_level_print()
30
38
 
39
+ cls.config_file_path = config_file_path
40
+ if config_file_path:
41
+ import configparser
42
+ config = configparser.ConfigParser()
43
+ config.read(config_file_path)
44
+ log_level = config.get("holado", "level")
45
+ log_on_console = config.get("holado", "log_on_console")
46
+ log_in_file = config.get("holado", "log_in_file")
47
+
31
48
  if log_level:
32
49
  if isinstance(log_level, str):
33
- cls.default_level = logging._nameToLevel[log_level]
34
- else:
35
- cls.default_level = log_level
50
+ log_level = logging._nameToLevel[log_level]
51
+ cls.default_level = log_level
52
+ if log_on_console:
53
+ if isinstance(log_on_console, str):
54
+ log_on_console = True if log_on_console == "True" else False
55
+ cls.log_on_console = log_on_console
56
+ if log_in_file:
57
+ if isinstance(log_in_file, str):
58
+ log_in_file = True if log_in_file == "True" else False
59
+ cls.log_in_file = log_in_file
60
+
61
+ if use_holado_logger:
62
+ cls.__set_holado_loggers()
36
63
 
37
- if initialize_logging:
38
- from holado_logging.common.logging.holado_logger import HALogger
39
-
40
- HALogger.default_message_size_limit = 10000
41
- cls.TLogger = HALogger
42
- cls.TManager = logging.Manager
43
-
44
- # Configure logging
45
- cls.configure_logging()
64
+ cls.__is_configured = True
46
65
 
47
66
  @classmethod
48
- def configure_logging(cls):
49
- #TODO EKL: make loggers configuration optional
50
- # Configure loggers
51
- from holado_logging.common.logging.holado_logger import TestRootLogger
52
- logging.root = TestRootLogger(cls.default_level)
67
+ def __set_holado_loggers(cls):
68
+ from holado_logging.common.logging.holado_logger import HALogger
69
+
70
+ # Configure loggers to use
71
+ HALogger.default_message_size_limit = 10000
72
+ cls.TLogger = HALogger
73
+ cls.TManager = logging.Manager
74
+
75
+ # Set loggers in logging
76
+ from holado_logging.common.logging.holado_logger import HARootLogger
77
+ logging.root = HARootLogger(cls.default_level)
53
78
  logging.Logger.root = logging.root
54
79
  logging.Logger.manager = cls.TManager(cls.TLogger.root)
55
80
 
@@ -63,28 +63,28 @@ class LogManager(object):
63
63
  self.format = '%(asctime)s | %(process)-5d-%(thread)-5d | %(levelname)5s | %(module)35s | %(message)s'
64
64
  self.style = '%'
65
65
 
66
- def initialize(self, log_on_console=True):
66
+ def configure(self):
67
+ self.__config_file_path = LogConfig.config_file_path
68
+
69
+ if self.__config_file_path:
70
+ config = configparser.ConfigParser()
71
+ config.read(self.__config_file_path)
72
+
73
+ if config.has_section("loggers_levels"):
74
+ self.__loggers_levels = config.items(section="loggers_levels")
75
+
76
+ def initialize(self):
67
77
  """
68
78
  Initialize log manager.
69
79
  If log_on_console is True, logs are published on console until a new configuration by calling method set_config
70
80
  """
71
- if log_on_console:
81
+ handlers = []
82
+ if LogConfig.log_on_console:
72
83
  self.on_console = True
73
84
  self.__console_handler = self.__new_console_handler()
74
- logging.basicConfig(format=self.format, style=self.style, level=LogConfig.default_level, handlers=[self.__console_handler])
75
- else:
76
- logging.basicConfig(format=self.format, style=self.style, level=LogConfig.default_level, handlers=[])
77
-
78
- def set_config_file_path(self, file_path, update_default_level=True):
79
- self.__config_file_path = file_path
85
+ handlers.append(self.__console_handler)
80
86
 
81
- config = configparser.ConfigParser()
82
- config.read(self.__config_file_path)
83
- if update_default_level:
84
- LogConfig.default_level = config.get("logger_root", "level")
85
-
86
- if config.has_section("loggers_levels"):
87
- self.__loggers_levels = config.items(section="loggers_levels")
87
+ logging.basicConfig(format=self.format, style=self.style, level=LogConfig.default_level, handlers=handlers)
88
88
 
89
89
  def has_log_file(self, file_name):
90
90
  with self.__files_lock:
@@ -154,8 +154,7 @@ class LogManager(object):
154
154
  # Update log destination to files
155
155
  with self.__files_lock:
156
156
  # Remove old log files
157
- # if self.__root_file_name:
158
- # self.remove_root_file_handler(do_reset=True)
157
+ # Note: root file is not removed if it is configured
159
158
  for file_name in list(self.__file_handlers.keys()):
160
159
  if file_name not in self.__file_names:
161
160
  self.remove_file_handler(file_name, do_remove_log_file=False)
@@ -166,7 +165,6 @@ class LogManager(object):
166
165
  for file_name in self.__file_names:
167
166
  if file_name not in list(self.__file_handlers.keys()):
168
167
  self.add_file_handler(file_name)
169
-
170
168
 
171
169
  # level
172
170
  if logger_.getEffectiveLevel() != LogConfig.default_level:
@@ -176,7 +174,10 @@ class LogManager(object):
176
174
  for name, level in self.__loggers_levels:
177
175
  if not name.startswith("#"):
178
176
  logging.getLogger(name).setLevel(level)
179
-
177
+
178
+ # WARNING: For local debug only
179
+ # logging.getLogger("holado_logging.common.logging.log_manager").setLevel(logging.DEBUG)
180
+
180
181
  def set_level(self, log_level, do_set_config=True):
181
182
  from holado_core.common.exceptions.technical_exception import TechnicalException
182
183
 
@@ -187,7 +187,7 @@ class MultitaskManager(object):
187
187
 
188
188
  def prepare_thread(self, name, update_parent=True):
189
189
  """
190
- Create a process context and return a unique name based to given name
190
+ Create a thread context and return a unique name based to given name
191
191
  """
192
192
  with self.__thread_lock:
193
193
  res = name
@@ -21,6 +21,7 @@ from holado_python.standard_library.typing import Typing
21
21
  from holado.common.handlers.undefined import undefined_argument, default_context
22
22
  from holado_core.common.exceptions.technical_exception import TimeoutTechnicalException
23
23
  from holado_core.common.exceptions.functional_exception import FunctionalException
24
+ from holado_python.common.tools.datetime import DateTime, FORMAT_DATETIME_ISO
24
25
 
25
26
  logger = logging.getLogger(__name__)
26
27
 
@@ -35,7 +36,8 @@ class Thread(threading.Thread):
35
36
  default_wait_timeout = Config.timeout_seconds * 1000
36
37
 
37
38
  self.__name = name
38
- self.__unique_name = SessionContext.instance().multitask_manager.prepare_thread(name)
39
+ # Note: if SessionContext doesn't have an instance (like during session context reset), use name+now as unique name
40
+ self.__unique_name = SessionContext.instance().multitask_manager.prepare_thread(name) if SessionContext.has_instance() else f"{name}_{DateTime.datetime_2_str(DateTime.now(), FORMAT_DATETIME_ISO)}"
39
41
  self.__default_wait_timeout = default_wait_timeout
40
42
  self.__delay_before_run_sec = delay_before_run_sec
41
43
 
@@ -48,7 +50,8 @@ class Thread(threading.Thread):
48
50
  self._is_idle.set()
49
51
 
50
52
  # Register thread
51
- if register_thread:
53
+ # Note: Do not register thread if session context doesn't have an instance (like during session context reset)
54
+ if register_thread and SessionContext.has_instance():
52
55
  # Registered name has to be unique
53
56
  SessionContext.instance().threads_manager.register_thread(self.__unique_name, self, scope=register_scope)
54
57
 
@@ -74,13 +77,14 @@ class Thread(threading.Thread):
74
77
 
75
78
  def _set_ident(self):
76
79
  super()._set_ident()
77
- if not MultitaskManager.has_thread_native_id():
80
+ if not MultitaskManager.has_thread_native_id() and SessionContext.has_instance():
78
81
  SessionContext.instance().multitask_manager.set_thread_uid(self.__unique_name, MultitaskManager.get_thread_uid(thread=self))
79
82
 
80
83
  if MultitaskManager.has_thread_native_id():
81
84
  def _set_native_id(self):
82
85
  super()._set_native_id()
83
- SessionContext.instance().multitask_manager.set_thread_uid(self.__unique_name, MultitaskManager.get_thread_uid(thread=self))
86
+ if SessionContext.has_instance():
87
+ SessionContext.instance().multitask_manager.set_thread_uid(self.__unique_name, MultitaskManager.get_thread_uid(thread=self))
84
88
 
85
89
  def join(self, timeout=undefined_argument, raise_if_still_alive=True):
86
90
  """
@@ -301,7 +301,7 @@ class ProtobufMessages(object):
301
301
  if ValueTableManager.verify_table_is_name_value_table(fields_table, raise_exception=False):
302
302
  self.__set_object_fields_with_name_value_table(res, fields_table)
303
303
  else:
304
- raise TechnicalException(f"When defining parameter fields_table, it must be a Name/Value table")
304
+ raise TechnicalException(f"When defining parameter fields_table, it must be a Name/Value table: [{Typing.get_object_class_fullname(fields_table)}]\n{fields_table.represent(4)}")
305
305
  elif fields_dict is not None:
306
306
  self.__set_object_fields_with_dict(res, fields_dict)
307
307
 
@@ -11,6 +11,7 @@
11
11
  #################################################
12
12
 
13
13
  import copy
14
+ from holado.common.handlers.undefined import undefined_value
14
15
 
15
16
 
16
17
  class EvaluateParameters(object):
@@ -23,7 +24,8 @@ class EvaluateParameters(object):
23
24
 
24
25
  def __init__(self, do_interpret=True, do_eval_variable=True, do_eval=True, \
25
26
  raise_on_interpret_error=True, raise_on_variable_eval_error=True, raise_on_eval_error=True,
26
- do_interpret_recursively=False, do_eval_variable_recursively=False):
27
+ do_interpret_recursively=False, do_eval_variable_recursively=False,
28
+ result_type=undefined_value):
27
29
  """
28
30
  Constructor
29
31
  @param
@@ -36,9 +38,11 @@ class EvaluateParameters(object):
36
38
  self.raise_on_interpret_error = raise_on_interpret_error
37
39
  self.raise_on_variable_eval_error = raise_on_variable_eval_error
38
40
  self.raise_on_eval_error = raise_on_eval_error
41
+ self.result_type = result_type
42
+ self.result_is_str = result_type is str
39
43
 
40
44
  def __str__(self)->str:
41
- return f"{{interpret:({self.do_interpret},recursive:{self.do_interpret_recursively},raise:{self.raise_on_interpret_error}) ; eval variable:({self.do_eval_variable},recursive:{self.do_eval_variable_recursively},raise:{self.raise_on_variable_eval_error}) ; eval:({self.do_eval},raise:{self.raise_on_eval_error})}}"
45
+ return f"{{interpret:({self.do_interpret},recursive:{self.do_interpret_recursively},raise:{self.raise_on_interpret_error}) ; eval variable:({self.do_eval_variable},recursive:{self.do_eval_variable_recursively},raise:{self.raise_on_variable_eval_error}) ; eval:({self.do_eval},raise:{self.raise_on_eval_error}) ; result type:{self.result_type}}}"
42
46
 
43
47
  def with_interpret(self, do_interpret):
44
48
  """
@@ -160,6 +164,20 @@ class EvaluateParameters(object):
160
164
  @return Same parameters but without raise
161
165
  """
162
166
  return self.with_raise(False)
167
+
168
+ def with_result_type(self, result_type=undefined_value):
169
+ """
170
+ Note: if result_type types are same, self instance is returned, else a new one is returned
171
+ @param result_type Evaluation result type
172
+ @return Same parameters but with result_type
173
+ """
174
+ if self.result_type == result_type:
175
+ return self
176
+ else:
177
+ res = copy.deepcopy(self)
178
+ res.result_type = result_type
179
+ res.result_is_str = result_type is str
180
+ return res
163
181
 
164
182
  @staticmethod
165
183
  def default(raise_exception=True):
@@ -178,7 +196,7 @@ class EvaluateParameters(object):
178
196
  @return Default evaluate parameters with raises
179
197
  """
180
198
  if EvaluateParameters.__instance_default is None:
181
- EvaluateParameters.__instance_default = EvaluateParameters(True, True, True, True, True, True)
199
+ EvaluateParameters.__instance_default = EvaluateParameters(True, True, True, True, True, True, undefined_value)
182
200
  return EvaluateParameters.__instance_default
183
201
 
184
202
  @staticmethod
@@ -187,7 +205,7 @@ class EvaluateParameters(object):
187
205
  @return Default evaluate parameters without any raise
188
206
  """
189
207
  if EvaluateParameters.__instance_default_without_raise is None:
190
- EvaluateParameters.__instance_default_without_raise = EvaluateParameters(True, True, True, False, False, False)
208
+ EvaluateParameters.__instance_default_without_raise = EvaluateParameters(True, True, True, False, False, False, undefined_value)
191
209
  return EvaluateParameters.__instance_default_without_raise
192
210
 
193
211
  @staticmethod
@@ -204,7 +222,7 @@ class EvaluateParameters(object):
204
222
  @return Default evaluate parameters without any raise
205
223
  """
206
224
  if EvaluateParameters.__instance_nothing is None:
207
- EvaluateParameters.__instance_nothing = EvaluateParameters(False, False, False, False, False, False)
225
+ EvaluateParameters.__instance_nothing = EvaluateParameters(False, False, False, False, False, False, undefined_value)
208
226
  return EvaluateParameters.__instance_nothing
209
227
 
210
228