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
@@ -25,7 +25,7 @@ from holado_scripting.common.tools.evaluate_parameters import EvaluateParameters
25
25
  from holado.holado_config import Config
26
26
  from holado_multitask.multitasking.multitask_manager import MultitaskManager
27
27
  from holado_python.standard_library.typing import Typing
28
- from holado.common.handlers.undefined import undefined_value
28
+ from holado.common.handlers.undefined import undefined_value, not_applicable
29
29
 
30
30
  logger = logging.getLogger(__name__)
31
31
 
@@ -47,52 +47,49 @@ class ExpressionEvaluator(object):
47
47
  self.__variable_manager = variable_manager
48
48
 
49
49
  def evaluate_expression(self, expression, unescape_string_method=None, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
50
- value_type, value, value_to_eval = self.extract_expression_information(expression, unescape_string_method)
50
+ value_type, value, value_to_eval = self.extract_expression_information(expression, unescape_string_method, eval_params=eval_params)
51
51
  if value_to_eval is not undefined_value:
52
- res = self.evaluate_expression_of_information(value_type, value_to_eval, eval_params=eval_params)
52
+ if ValueTypes.is_string(value_type):
53
+ eval_params = eval_params.with_result_type(str)
54
+ res_type, res = self.evaluate_expression_of_information(value_type, value_to_eval, eval_params=eval_params, log_level=log_level)
55
+ if Tools.do_log(logger, log_level):
56
+ logger.log(log_level, f"Evaluate expression [{expression}] => ({value_type.name}, {value}, '{value_to_eval}') => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
53
57
  else:
54
- res = value
55
- if Tools.do_log(logger, log_level):
56
- logger.log(log_level, f"Evaluate expression [{expression}] => ({value_type}, {value}, '{value_to_eval}') => [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
57
- return res
58
+ res_type, res = value_type, value
59
+ if Tools.do_log(logger, log_level):
60
+ logger.log(log_level, f"Evaluate expression [{expression}] => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
61
+ return res_type, res
58
62
 
59
63
  def evaluate_python_expression(self, expression, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
60
- res = self.evaluate_expression_of_information(ValueTypes.Symbol, expression, eval_params=eval_params)
64
+ res_type, res = self.evaluate_expression_of_information(ValueTypes.Symbol, expression, eval_params=eval_params, log_level=log_level)
61
65
  if Tools.do_log(logger, log_level):
62
- logger.log(log_level, f"Evaluate python expression [{expression}] => [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
63
- return res
66
+ logger.log(log_level, f"Evaluate python expression [{expression}] => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
67
+ return res_type, res
64
68
 
65
- def extract_expression_information(self, expression, unescape_string_method=None, log_level=logging.TRACE): # @UndefinedVariable
66
- res = self.__extract_expression_information(expression, unescape_string_method=unescape_string_method)
69
+ def extract_expression_information(self, expression, unescape_string_method=None, eval_params=EvaluateParameters.default(), log_level=logging.TRACE): # @UndefinedVariable
70
+ res = self.__extract_expression_information(expression, unescape_string_method=unescape_string_method, eval_params=eval_params)
67
71
  if Tools.do_log(logger, log_level):
68
72
  logger.log(log_level, f"Extract expression information [{expression}] => {res}")
69
73
  return res
70
74
 
71
- def __extract_expression_information(self, expression, unescape_string_method=None):
75
+ def __extract_expression_information(self, expression, unescape_string_method=None, eval_params=EvaluateParameters.default()):
72
76
  if isinstance(expression, str):
73
- return self.__extract_expression_information_str(expression, unescape_string_method = unescape_string_method)
77
+ return self.__extract_expression_information_str(expression, unescape_string_method=unescape_string_method, eval_params=eval_params)
74
78
  else:
75
- return self.__extract_value_information(expression)
79
+ return (*self.__extract_value_information(expression, from_symbol=False, from_str=False), undefined_value)
76
80
 
77
- def __extract_expression_information_str(self, expression, unescape_string_method=None):
81
+ def __extract_expression_information_str(self, expression, unescape_string_method=None, eval_params=EvaluateParameters.default()):
78
82
  if unescape_string_method is None:
79
83
  from holado_test.scenario.step_tools import StepTools
80
84
  unescape_string_method = StepTools.unescape_string
81
85
 
82
86
  try:
83
87
  expr_content = expression.strip()
84
-
85
- # Manage usual types
86
- if expr_content == Config.NONE_SYMBOL:
87
- return (ValueTypes.Null, None, undefined_value)
88
- elif expr_content == Config.NOT_APPLICABLE_SYMBOL:
89
- return (ValueTypes.NotApplicable, undefined_value, undefined_value)
90
- elif Converter.is_boolean(expr_content):
91
- return (ValueTypes.Boolean, Converter.to_boolean(expr_content), undefined_value)
92
- elif Converter.is_integer(expr_content):
93
- return (ValueTypes.Integer, int(expr_content), undefined_value)
94
- elif Converter.is_float(expr_content):
95
- return (ValueTypes.Float, float(expr_content), undefined_value)
88
+
89
+ # Manage usual types
90
+ value_type, value = self.__extract_value_information(expr_content, from_symbol=not eval_params.result_is_str, from_str=not eval_params.result_is_str)
91
+ if value_type != ValueTypes.String:
92
+ return (value_type, value, undefined_value)
96
93
 
97
94
  # Manage strings
98
95
  for end_sym, val_type in [(Config.DYNAMIC_SYMBOL, ValueTypes.DynamicString),
@@ -104,73 +101,73 @@ class ExpressionEvaluator(object):
104
101
  if unescape_string_method is not None:
105
102
  text = unescape_string_method(text)
106
103
  return (val_type, undefined_value, text)
107
-
108
- # # Manage evaluated values
109
- # try:
110
- # value_evaluated = eval(expr_content)
111
- # evaluated = True
112
- # except (SyntaxError, NameError, ValueError):
113
- # evaluated = False
114
- # if evaluated:
115
- # if isinstance(value_evaluated, bool):
116
- # value_type = ValueTypes.Boolean
117
- # elif isinstance(value_evaluated, int):
118
- # value_type = ValueTypes.Integer
119
- # elif isinstance(value_evaluated, float):
120
- # value_type = ValueTypes.Float
121
- # elif isinstance(value_evaluated, str):
122
- # value_type = ValueTypes.String
123
- # else:
124
- # value_type = ValueTypes.Generic
125
- # return (value_type, value_evaluated)
126
104
 
127
105
  # Else consider content as a symbol
128
106
  return (ValueTypes.Symbol, undefined_value, expr_content)
129
107
  except Exception as exc:
130
108
  raise TechnicalException(f"Error while extracting expression information in expression [{expression}] (type: {Typing.get_object_class_fullname(expression)})") from exc
131
109
 
132
- def extract_value_information(self, value):
133
- return self.__extract_value_information(value)
110
+ def extract_value_information(self, value, *, from_symbol=True, from_str=True):
111
+ return self.__extract_value_information(value, from_symbol=from_symbol, from_str=from_str)
134
112
 
135
- def __extract_value_information(self, value):
113
+ def __extract_value_information(self, value, *, from_symbol=False, from_str=False):
136
114
  if value is undefined_value:
137
- return (ValueTypes.Undefined, undefined_value, undefined_value)
115
+ return (ValueTypes.Undefined, undefined_value)
116
+ elif value is not_applicable:
117
+ return (ValueTypes.NotApplicable, not_applicable)
138
118
  elif value is None:
139
- return (ValueTypes.Null, None, undefined_value)
119
+ return (ValueTypes.Null, None)
140
120
  elif isinstance(value, bool):
141
- return (ValueTypes.Boolean, value, undefined_value)
121
+ return (ValueTypes.Boolean, value)
142
122
  elif isinstance(value, int):
143
- return (ValueTypes.Integer, value, undefined_value)
123
+ return (ValueTypes.Integer, value)
144
124
  elif isinstance(value, float):
145
- return (ValueTypes.Float, value, undefined_value)
125
+ return (ValueTypes.Float, value)
146
126
  elif isinstance(value, str):
147
- return (ValueTypes.String, value, undefined_value)
127
+ if from_symbol:
128
+ if value == Config.NONE_SYMBOL:
129
+ return (ValueTypes.Null, None)
130
+ elif value == Config.NOT_APPLICABLE_SYMBOL:
131
+ return (ValueTypes.NotApplicable, not_applicable)
132
+
133
+ if from_str:
134
+ if Converter.is_boolean(value):
135
+ return (ValueTypes.Boolean, Converter.to_boolean(value))
136
+ elif Converter.is_integer(value):
137
+ return (ValueTypes.Integer, int(value))
138
+ elif Converter.is_float(value):
139
+ return (ValueTypes.Float, float(value))
140
+
141
+ return (ValueTypes.String, value)
148
142
  else:
149
- return (ValueTypes.Generic, value, undefined_value)
143
+ return (ValueTypes.Generic, value)
150
144
 
151
- def evaluate_expression_of_information(self, value_type, value, eval_params=EvaluateParameters.default()):
152
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
153
- logger.trace(f"Evaluating expression of information ({value_type.name}, {value}, {eval_params})")
154
- res = self.__evaluate_expression_of_information(value_type, value, eval_params=eval_params)
155
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
156
- logger.trace(f"Evaluate expression of information ({value_type.name}, {value}) => [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
157
- return res
145
+ def evaluate_expression_of_information(self, value_type, value, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
146
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
147
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluating expression of information ({value_type.name}, {value}, {eval_params})") # @UndefinedVariable
148
+ res_type, res = self.__evaluate_expression_of_information(value_type, value, eval_params=eval_params, log_level=log_level)
149
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
150
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluate expression of information ({value_type.name}, {value}) => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})") # @UndefinedVariable
151
+ return res_type, res
158
152
 
159
- def __evaluate_expression_of_information(self, value_type, value, eval_params=EvaluateParameters.default()):
160
- if value_type in [ValueTypes.Null]:
161
- return None
153
+ def __evaluate_expression_of_information(self, value_type, value, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
154
+ if value_type in [ValueTypes.NotApplicable]:
155
+ return (value_type, not_applicable)
156
+ elif value_type in [ValueTypes.Null]:
157
+ return (value_type, None)
162
158
  elif value_type in [ValueTypes.Boolean, ValueTypes.Integer, ValueTypes.Float, ValueTypes.Generic]:
163
- return value
164
- elif value_type in [ValueTypes.String, ValueTypes.DynamicString, ValueTypes.ThreadDynamicString, ValueTypes.UniqueString]:
165
- return self.__evaluate_expression_of_information_string(value_type, value, eval_params=eval_params)
159
+ return (value_type, value)
160
+ elif ValueTypes.is_string(value_type):
161
+ eval_params = eval_params.with_result_type(str)
162
+ return self.__evaluate_expression_of_information_string(value_type, value, eval_params=eval_params, log_level=log_level)
166
163
  elif value_type in [ValueTypes.Symbol]:
167
- return self.__evaluate_expression_of_information_symbol(value, eval_params=eval_params)
164
+ return self.__evaluate_expression_of_information_symbol(value, eval_params=eval_params, log_level=log_level)
168
165
  else:
169
- return value
166
+ return self.__extract_value_information(value)
170
167
 
171
- def __evaluate_expression_of_information_string(self, value_type, value, eval_params=EvaluateParameters.default_without_raise()):
168
+ def __evaluate_expression_of_information_string(self, value_type, value, eval_params=EvaluateParameters.default_without_raise(), log_level=logging.DEBUG):
172
169
  if eval_params.do_interpret:
173
- res = self.__text_interpreter.interpret(value, eval_params=eval_params)
170
+ res = self.__text_interpreter.interpret(value, eval_params=eval_params, log_level=log_level)
174
171
  else:
175
172
  res = value
176
173
 
@@ -180,75 +177,80 @@ class ExpressionEvaluator(object):
180
177
  res = str(res)
181
178
 
182
179
  if value_type == ValueTypes.DynamicString:
183
- return self.__dynamic_text_manager.get(res)
180
+ res = self.__dynamic_text_manager.get(res)
184
181
  elif value_type == ValueTypes.ThreadDynamicString:
185
- return self.__dynamic_text_manager.get(res, scope=MultitaskManager.get_thread_id())
182
+ res = self.__dynamic_text_manager.get(res, scope=MultitaskManager.get_thread_id())
186
183
  elif value_type == ValueTypes.UniqueString:
187
- return res + self.__unique_value_manager.new_string(padding_length=Config.unique_string_padding_length)
188
- else:
189
- return res
184
+ res = res + self.__unique_value_manager.new_string(padding_length=Config.unique_string_padding_length)
185
+
186
+ return self.extract_value_information(res, from_symbol=not eval_params.result_is_str, from_str=not eval_params.result_is_str)
190
187
 
191
- def __evaluate_expression_of_information_symbol(self, value, eval_params=EvaluateParameters.default()):
192
- if logger.isEnabledFor(logging.TRACE): # @UndefinedVariable
193
- logger.trace(f"Evaluating symbol ([{value}], {eval_params})")
188
+ def __evaluate_expression_of_information_symbol(self, value, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
189
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
190
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluating symbol ([{value}], {eval_params})") # @UndefinedVariable
194
191
  res = value
195
192
 
196
193
  # Replace explicit interpret parts
197
194
  if eval_params.do_interpret and isinstance(res, str):
198
- res, _, is_evaluated = self.__evaluate_interpret_expression(res, eval_params=eval_params)
195
+ res, _, is_evaluated = self.__evaluate_interpret_expression(res, eval_params=eval_params, log_level=log_level)
199
196
  if is_evaluated:
200
197
  # If symbol is already evaluated, stop evaluation process
201
- if logger.isEnabledFor(logging.TRACE): # @UndefinedVariable
202
- logger.trace(f"Evaluate symbol [{value}] => [{res}] (type: {Typing.get_object_class_fullname(res)}) (after interpret, with evaluate parameters: {eval_params})")
203
- return res
198
+ # Note: evaluation of string was already done if asked, thus just evaluate symbols
199
+ res_type, res = self.__extract_value_information(res, from_symbol=not eval_params.result_is_str, from_str=not eval_params.result_is_str)
200
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
201
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluate symbol [{value}] => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (after interpret, with evaluate parameters: {eval_params})") # @UndefinedVariable
202
+ return res_type, res
204
203
  # if logger.isEnabledFor(logging.TRACE): # @UndefinedVariable
205
204
  # logger.trace(f"Evaluate symbol [{value}] - after interpret: [{res}] (type: {Typing.get_object_class_fullname(res)}) (with evaluate parameters: {eval_params})")
206
205
 
207
206
  # Evaluate variable expression
208
207
  # Note: if an eval must be done after interpret, variable shouldn't be evaluated unless it can makes failing eval
209
208
  if eval_params.do_eval_variable and isinstance(res, str) and len(res) > 0:
210
- result, is_evaluated = self.__evaluate_variable_expression(res, eval_params=eval_params)
209
+ result, is_evaluated = self.__evaluate_variable_expression(res, eval_params=eval_params, log_level=log_level)
211
210
  if is_evaluated:
212
211
  # If symbol is a variable expression, don't evaluate the result of the variable
213
- if logger.isEnabledFor(logging.TRACE): # @UndefinedVariable
214
- logger.trace(f"Evaluate symbol [{value}] => [{result}] (type: {Typing.get_object_class_fullname(result)}) (after variable evaluation, with evaluate parameters: {eval_params})")
215
- return result
212
+ res_type, res = self.__extract_value_information(result, from_symbol=False, from_str=False)
213
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
214
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluate symbol [{value}] => ({res_type.name}) [{res}] (type: {Typing.get_object_class_fullname(res)}) (after variable evaluation, with evaluate parameters: {eval_params})") # @UndefinedVariable
215
+ return res_type, res
216
216
 
217
217
  # Evaluate expression
218
218
  # if eval_params.do_eval and (isinstance(res, str) or isinstance(res, bytes)): # Commented as it doesn't work currently with bytes
219
219
  if eval_params.do_eval and isinstance(res, str):
220
- res = self.__evaluate_expression(res, locals_={}, eval_params=eval_params)
220
+ res = self.__evaluate_expression(res, locals_={}, eval_params=eval_params, log_level=log_level)
221
221
 
222
222
  # logger.debug(f"Evaluate symbol [{value}] => [{res}] (type: {Typing.get_object_class_fullname(res)})")
223
- if logger.isEnabledFor(logging.TRACE): # @UndefinedVariable
224
- logger.trace(f"Evaluate symbol [{value}] => [{res}] (type: {Typing.get_object_class_fullname(res)}) (after full evaluation, with evaluate parameters: {eval_params})")
225
- return res
223
+ # Note: evaluation of string was already done if asked, thus just evaluate symbols
224
+ res_type, res = self.__extract_value_information(res, from_symbol=not eval_params.result_is_str, from_str=not eval_params.result_is_str)
225
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
226
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Evaluate symbol [{value}] => [{res}] (type: {Typing.get_object_class_fullname(res)}) (after full evaluation, with evaluate parameters: {eval_params})") # @UndefinedVariable
227
+ return res_type, res
226
228
 
227
- def __evaluate_interpret_expression(self, value, eval_params=EvaluateParameters.default()):
229
+ def __evaluate_interpret_expression(self, value, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
228
230
  result, is_interpreted, is_evaluated = value, False, False
229
231
 
230
232
  nb_sections = self.__text_interpreter.get_number_of_sections(value)
231
233
  if nb_sections > 0:
232
234
  # If eval is authorized, and many sections exists, prefer interpret sections and eval result
233
235
  if eval_params.do_eval and nb_sections > 1:
234
- result, locals_ = self.__text_interpreter._interpret_sections(value, eval_params=eval_params)
236
+ result, locals_ = self.__text_interpreter._interpret_sections(value, eval_params=eval_params, log_level=log_level)
235
237
  if result != value:
236
- result = self.__evaluate_expression(result, locals_, eval_params=eval_params)
238
+ result = self.__evaluate_expression(result, locals_, eval_params=eval_params, log_level=log_level)
237
239
  is_evaluated = True
238
240
  else:
239
- result = self.__text_interpreter.interpret(value, eval_params=eval_params)
241
+ result = self.__text_interpreter.interpret(value, eval_params=eval_params, log_level=log_level)
240
242
  is_interpreted = result != value
241
243
 
242
244
  # Manage recursive interpret, only in case of first interpret and if it wasn't evaluated
243
245
  if eval_params.do_interpret_recursively and is_interpreted and not is_evaluated and isinstance(result, str):
244
- new_result, new_is_interpreted, new_is_evaluated = self.__evaluate_interpret_expression(result, eval_params.with_raise_on_interpret_error(False))
246
+ new_result, new_is_interpreted, new_is_evaluated = self.__evaluate_interpret_expression(result, eval_params.with_raise_on_interpret_error(False), log_level=log_level)
245
247
  if new_is_interpreted:
246
248
  result = new_result
247
249
  is_evaluated = new_is_evaluated
248
250
 
249
251
  return result, is_interpreted, is_evaluated
250
252
 
251
- def __evaluate_variable_expression(self, value, eval_params=EvaluateParameters.default()):
253
+ def __evaluate_variable_expression(self, value, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
252
254
  is_evaluated, result = False, None
253
255
 
254
256
  if self.__variable_manager.exists_variable(value):
@@ -261,20 +263,20 @@ class ExpressionEvaluator(object):
261
263
  if eval_params.raise_on_variable_eval_error:
262
264
  raise exc
263
265
  else:
264
- # logger.error(f"Error while evaluating variable expression [{value}]: {exc}")
265
- logger.error(f"Error while evaluating variable expression [{value}]: {Tools.represent_exception(exc)}\n -> traceback:\n{traceback.represent_stack(indent=4)}")
266
+ if Tools.do_log(logger, log_level):
267
+ logger.log(log_level, f"Error while evaluating variable expression [{value}]: {Tools.represent_exception(exc)}\n -> traceback:\n{traceback.represent_stack(indent=4)}")
266
268
  else:
267
269
  is_evaluated = True
268
270
 
269
271
  # Manage recursive evaluation, only in case of first variable evaluation
270
272
  if eval_params.do_eval_variable_recursively and is_evaluated and isinstance(result, str) and result != value:
271
- new_result, new_is_evaluated = self.__evaluate_variable_expression(result, eval_params.with_raise_on_variable_eval_error(False))
273
+ new_result, new_is_evaluated = self.__evaluate_variable_expression(result, eval_params.with_raise_on_variable_eval_error(False), log_level=log_level)
272
274
  if new_is_evaluated:
273
275
  result = new_result
274
276
 
275
277
  return result, is_evaluated
276
278
 
277
- def __evaluate_expression(self, value, locals_, eval_params=EvaluateParameters.default()):
279
+ def __evaluate_expression(self, value, locals_, eval_params=EvaluateParameters.default(), log_level=logging.DEBUG):
278
280
  res = value
279
281
  while True:
280
282
  try:
@@ -301,20 +303,20 @@ class ExpressionEvaluator(object):
301
303
 
302
304
  # If no import is done
303
305
  if not is_imported:
304
- if Tools.do_log(logger, logging.DEBUG):
305
- logger.debug(f"Error while evaluating expression [{value}]: {exc}")
306
+ if Tools.do_log(logger, logging.DEBUG, max_log_level=log_level):
307
+ logger.log(Tools.do_log_level(logging.DEBUG, log_level), f"Error while evaluating expression [{value}]: {exc}")
306
308
  break
307
309
  except Exception as exc:
308
310
  if eval_params.raise_on_eval_error:
309
311
  raise exc
310
312
  else:
311
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
312
- logger.trace(f"Error while evaluating expression [{value}]: {Tools.represent_exception(exc)}")
313
- elif Tools.do_log(logger, logging.DEBUG):
313
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
314
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), f"Error while evaluating expression [{value}]: {Tools.represent_exception(exc)}") # @UndefinedVariable
315
+ elif Tools.do_log(logger, logging.DEBUG, max_log_level=log_level):
314
316
  if isinstance(exc, SyntaxError):
315
- logger.debug(f"Error while evaluating expression [{value}]: {repr(exc)}")
317
+ logger.log(Tools.do_log_level(logging.DEBUG, log_level), f"Error while evaluating expression [{value}]: {repr(exc)}")
316
318
  else:
317
- logger.debug(f"Error while evaluating expression [{value}]: [{Typing.get_object_class_fullname(exc)}] {exc}")
319
+ logger.log(Tools.do_log_level(logging.DEBUG, log_level), f"Error while evaluating expression [{value}]: [{Typing.get_object_class_fullname(exc)}] {exc}")
318
320
  break
319
321
  else:
320
322
  if not isinstance(result, types.ModuleType):
@@ -374,7 +376,7 @@ class ExpressionEvaluator(object):
374
376
 
375
377
  def extract_string_value(self, expression, unescape_string_method=None, log_level=logging.DEBUG):
376
378
  value_type, value_str, value_to_eval = self.extract_expression_information(expression, unescape_string_method)
377
- if value_type in [ValueTypes.String, ValueTypes.DynamicString, ValueTypes.ThreadDynamicString, ValueTypes.UniqueString]:
379
+ if ValueTypes.is_string(value_type):
378
380
  if value_to_eval is not undefined_value:
379
381
  res = value_to_eval
380
382
  else:
@@ -382,6 +384,6 @@ class ExpressionEvaluator(object):
382
384
  else:
383
385
  res = expression
384
386
  if Tools.do_log(logger, log_level):
385
- logger.debug(f"Extract string value [{expression}] => ({value_type}, '{value_str}') => [{res}] (type: {Typing.get_object_class_fullname(res)})")
387
+ logger.log(log_level, f"Extract string value [{expression}] => ({value_type}, '{value_str}') => [{res}] (type: {Typing.get_object_class_fullname(res)})")
386
388
  return res
387
389
 
@@ -49,7 +49,7 @@ def __get_expression_evaluator():
49
49
  def step_impl(context, condition_expression):
50
50
  __get_scope_manager().log_conditions_info(f"Before evaluation of if condition expression [{condition_expression}]")
51
51
  __get_scope_manager().increase_condition_level()
52
- cond = __get_expression_evaluator().evaluate_python_expression(condition_expression)
52
+ _, cond = __get_expression_evaluator().evaluate_python_expression(condition_expression)
53
53
  if isinstance(cond, bool) or Converter.is_boolean(cond):
54
54
  if isinstance(cond, bool) and cond or Converter.is_boolean(cond) and Converter.to_boolean(cond):
55
55
  __get_scope_manager().enter_in_valid_condition()
@@ -61,7 +61,7 @@ def step_impl(context, condition_expression):
61
61
  def step_impl(context, condition_expression):
62
62
  __get_scope_manager().leave_condition()
63
63
  if not __get_scope_manager().had_valid_condition():
64
- cond = __get_expression_evaluator().evaluate_python_expression(condition_expression)
64
+ _, cond = __get_expression_evaluator().evaluate_python_expression(condition_expression)
65
65
  if isinstance(cond, bool) or Converter.is_boolean(cond):
66
66
  if isinstance(cond, bool) and cond or Converter.is_boolean(cond) and Converter.to_boolean(cond):
67
67
  __get_scope_manager().enter_in_valid_condition()
@@ -38,7 +38,7 @@ class FunctionHexToBytes(BaseFunction):
38
38
 
39
39
  # Evaluate parameter
40
40
  if isinstance(src, str):
41
- src_eval = self.__expression_evaluator.evaluate_expression(src)
41
+ _, src_eval = self.__expression_evaluator.evaluate_expression(src)
42
42
  if isinstance(src_eval, bytes) or isinstance(src_eval, str):
43
43
  src = src_eval
44
44
  else:
@@ -60,12 +60,11 @@ class TextInterpreter(TextInspecter):
60
60
  if str_to_interpret is None:
61
61
  return None
62
62
 
63
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
64
-
65
- logger.trace("Interpreting '{}'...".format(str_to_interpret))
63
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
64
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), "Interpreting '{}'...".format(str_to_interpret)) # @UndefinedVariable
66
65
 
67
66
  # Interpret and get result as object
68
- res, _ = self.__interpret(str_to_interpret, eval_params=eval_params)
67
+ res, _ = self.__interpret(str_to_interpret, eval_params=eval_params, log_level=log_level)
69
68
 
70
69
  if Tools.do_log_if_objects_are_different(logger, log_level, str_to_interpret, res):
71
70
  logger.log(log_level, "Interpreting '{}' -> [{}] (type: {})".format(str_to_interpret, res, type(res)))
@@ -82,18 +81,17 @@ class TextInterpreter(TextInspecter):
82
81
  if str_to_interpret is None:
83
82
  return None
84
83
 
85
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
86
-
87
- logger.trace("Interpreting sections in '{}'...".format(str_to_interpret))
84
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
85
+ logger.log(Tools.do_log_level(logging.TRACE, log_level), "Interpreting sections in '{}'...".format(str_to_interpret)) # @UndefinedVariable
88
86
 
89
87
  # Interpret and get result as object
90
- res, locals_ = self.__interpret(str_to_interpret, replace_sections_by_variables=True, eval_params=eval_params)
88
+ res, locals_ = self.__interpret(str_to_interpret, replace_sections_by_variables=True, eval_params=eval_params, log_level=log_level)
91
89
 
92
90
  if Tools.do_log_if_objects_are_different(logger, log_level, str_to_interpret, res):
93
91
  logger.log(log_level, f"Interpreting sections in '{str_to_interpret}' -> [{res}] (type: {type(res)}, locals: {locals_})")
94
92
  return res, locals_
95
93
 
96
- def __interpret(self, str_to_interpret, replace_sections_by_variables=False, eval_params=EvaluateParameters.default_without_raise()):
94
+ def __interpret(self, str_to_interpret, replace_sections_by_variables=False, eval_params=EvaluateParameters.default_without_raise(), log_level=logging.DEBUG):
97
95
  res = None
98
96
  locals_ = {}
99
97
 
@@ -103,7 +101,7 @@ class TextInterpreter(TextInspecter):
103
101
  r_match = self.__regex_to_be_interpreted.match(str_to_interpret)
104
102
  if r_match:
105
103
  str_under_interpret = r_match.group(1).strip()
106
- res = self.__interpret_text(str_under_interpret, eval_params=eval_params)
104
+ res = self.__interpret_text(str_under_interpret, eval_params=eval_params, log_level=log_level)
107
105
  # Text is not interpretable ; expect it will be the case later
108
106
  if res == str_under_interpret:
109
107
  res = str_to_interpret
@@ -112,19 +110,20 @@ class TextInterpreter(TextInspecter):
112
110
  else:
113
111
  raise TechnicalException(f"Failed to find interpret section whereas its indexes were found")
114
112
  else:
115
- res, locals_ = self.__find_and_interpret_sections(str_to_interpret, replace_sections_by_variables=replace_sections_by_variables, eval_params=eval_params)
113
+ res, locals_ = self.__find_and_interpret_sections(str_to_interpret, replace_sections_by_variables=replace_sections_by_variables, eval_params=eval_params, log_level=log_level)
116
114
 
117
115
  return res, locals_
118
116
 
119
- def __interpret_text(self, text, eval_params=EvaluateParameters.default_without_raise()):
117
+ def __interpret_text(self, text, eval_params=EvaluateParameters.default_without_raise(), log_level=logging.DEBUG): # @UndefinedVariable
120
118
  # Manage functions
121
119
  if self._has_function(text, with_interpreted=False):
122
- return self.__evaluate_function(text, eval_params=eval_params)
120
+ return self.__evaluate_function(text, eval_params=eval_params, log_level=log_level)
123
121
 
124
122
  # Manage evaluation
125
- return self._expression_evaluator.evaluate_expression(text, eval_params=eval_params, log_level=logging.TRACE) # @UndefinedVariable
123
+ _, res = self._expression_evaluator.evaluate_expression(text, eval_params=eval_params, log_level=Tools.do_log_level(log_level, logging.TRACE)) # @UndefinedVariable
124
+ return res
126
125
 
127
- def __find_and_interpret_sections(self, str_to_interpret, replace_sections_by_variables=False, eval_params=EvaluateParameters.default_without_raise()):
126
+ def __find_and_interpret_sections(self, str_to_interpret, replace_sections_by_variables=False, eval_params=EvaluateParameters.default_without_raise(), log_level=logging.DEBUG):
128
127
  res = str_to_interpret
129
128
  locals_ = {}
130
129
 
@@ -145,7 +144,7 @@ class TextInterpreter(TextInspecter):
145
144
  sub_str = res[ind_beg:ind_end]
146
145
 
147
146
  # Interpret sub-section
148
- interpreted_value = self.interpret(sub_str, eval_params=eval_params)
147
+ interpreted_value = self.interpret(sub_str, eval_params=eval_params, log_level=log_level)
149
148
 
150
149
  # Manage sections that aren't interpretable
151
150
  interpreted_str = f"{interpreted_value}"
@@ -170,7 +169,7 @@ class TextInterpreter(TextInspecter):
170
169
 
171
170
  return res, locals_
172
171
 
173
- def __evaluate_function(self, fct_str, eval_params=EvaluateParameters.default_without_raise()):
172
+ def __evaluate_function(self, fct_str, eval_params=EvaluateParameters.default_without_raise(), log_level=logging.DEBUG):
174
173
  func_name, args_str = self._get_function_and_args_strings(fct_str, with_interpreted=False)
175
174
  func = self._get_function(func_name) if func_name is not None else None
176
175
  if func is None:
@@ -178,8 +177,8 @@ class TextInterpreter(TextInspecter):
178
177
 
179
178
  args = self._get_args(args_str)
180
179
 
181
- if Tools.do_log(logger, logging.TRACE): # @UndefinedVariable
182
- logger.trace(f"Evaluating function '{func_name}' with args {args}")
180
+ if Tools.do_log(logger, logging.TRACE, max_log_level=log_level): # @UndefinedVariable
181
+ logger.log(Tools.do_log_level(logging.TRACE, max_log_level=log_level), f"Evaluating function '{func_name}' with args {args}") # @UndefinedVariable
183
182
  # logger.trace(f"Evaluating function '{func_name}' with args {args} (eval_params: {eval_params})", stack_info=True)
184
183
  try:
185
184
  res = func.apply(args)
@@ -189,8 +188,8 @@ class TextInterpreter(TextInspecter):
189
188
  else:
190
189
  res = fct_str
191
190
 
192
- if Tools.do_log(logger, logging.DEBUG):
193
- logger.debug(f"Evaluate function [{fct_str}] => [{func_name}({', '.join(args)})] => [{res}] (type: {Typing.get_object_class_fullname(res)})")
191
+ if Tools.do_log(logger, log_level):
192
+ logger.log(log_level, f"Evaluate function [{fct_str}] => [{func_name}({', '.join(args)})] => [{res}] (type: {Typing.get_object_class_fullname(res)})")
194
193
  return res
195
194
 
196
195
  def __register_default_functions(self, dynamic_text_manager):
@@ -22,6 +22,8 @@ from holado_test.behave.scenario.behave_step_tools import BehaveStepTools
22
22
  from holado_test.scenario.step_tools import StepTools
23
23
  from holado_test.test_config import TestConfig
24
24
  import time
25
+ from behave.model_core import Status
26
+ from holado.common.handlers.undefined import undefined_value
25
27
 
26
28
 
27
29
  logger = logging.getLogger(__name__)
@@ -107,23 +109,40 @@ def after_step(context, step):
107
109
  # Session context
108
110
  SessionContext.instance().after_step(step)
109
111
 
110
- # Log failures
111
- if step.status == "failed":
112
- step_descr = __step_description(step)
113
- var_step_descr = StepTools.evaluate_variable_name(step_descr)
114
- interpreted_step_descr = StepTools.evaluate_string_parameter(step_descr)
115
- msg = "Step failed:\n step:\n{}{}{}\n error:\n{}\n step attributes:\n{}".format(
116
- Tools.indent_string(8, step_descr),
112
+ # Log step result
113
+ step_descr = __step_description(step)
114
+ try:
115
+ var_step_descr = StepTools.evaluate_variable_name(step_descr, log_level=logging.NOTSET)
116
+ except:
117
+ var_step_descr = "[ERROR during evaluation]"
118
+ try:
119
+ interpreted_step_descr = StepTools.evaluate_string_parameter(step_descr, log_level=logging.NOTSET)
120
+ except:
121
+ interpreted_step_descr = "[ERROR during interpretation]"
122
+ if step.status in [Status.failed, Status.error] or interpreted_step_descr != step_descr or var_step_descr != interpreted_step_descr:
123
+ msg = "Step {}:\n step:\n{}{}{}".format(
124
+ step.status.name, Tools.indent_string(8, step_descr),
117
125
  "" if interpreted_step_descr == step_descr else "\n interpreted step:\n{}".format(Tools.indent_string(8, interpreted_step_descr)),
118
- "" if var_step_descr == interpreted_step_descr else "\n partially interpreted step:\n{}".format(Tools.indent_string(8, var_step_descr)),
119
- Tools.indent_string(8, __step_error(step)),
120
- Tools.indent_string(8, __step_attributes(step)) )
121
- if step.hook_failed:
122
- msg += "\n Hook failed"
126
+ "" if var_step_descr == interpreted_step_descr else "\n partially interpreted step:\n{}".format(Tools.indent_string(8, var_step_descr)) )
127
+
128
+ if step.status in [Status.failed, Status.error]:
129
+ msg += "\n error:\n{}\n step attributes:\n{}".format(
130
+ Tools.indent_string(8, __step_error(step)),
131
+ Tools.indent_string(8, __step_attributes(step)) )
132
+ if step.hook_failed:
133
+ msg += "\n Hook failed"
134
+ elif '\n' in step_descr:
135
+ msg = "Step {}:\n{}".format(step.status.name, Tools.indent_string(4, step_descr))
136
+ else:
137
+ msg = "Step {}: {}".format(step.status.name, step_descr)
138
+
139
+ if step.status in [Status.failed, Status.error]:
123
140
  logger.error(msg)
124
141
 
125
142
  if TestConfig.wait_on_step_failure_s > 0:
126
143
  time.sleep(TestConfig.wait_on_step_failure_s)
144
+ else:
145
+ logger.debug(msg)
127
146
  except:
128
147
  logger.exception(f"Hook error (step: {step})")
129
148
  raise
@@ -14,6 +14,7 @@
14
14
  import logging
15
15
  from behave.runner import Runner
16
16
  from behave.parser import parse_feature
17
+ from holado.holado_config import Config
17
18
 
18
19
 
19
20
  logger = logging.getLogger(__name__)
@@ -55,12 +56,9 @@ class IndependantRunner(Runner):
55
56
  feature_text = \
56
57
  """
57
58
  Feature: Fake
58
-
59
59
  Scenario: Fake
60
- # Wait 7 days
61
- Given DELAY = ${7 * 24 * 3600}
62
- When wait DELAY seconds
63
- """
60
+ When wait {runner_session_timeout} seconds
61
+ """.format(runner_session_timeout=Config.session_timeout_seconds)
64
62
  feature = parse_feature(feature_text)
65
63
 
66
64
  return super().run_model([feature])