def test_different_os_positive(mocked_run_osie, slug): handler = mocked_run_osie d = copy.deepcopy(cacher_provisioning) dpath.new(d, "instance/operating_system_version/os_slug", slug) c = ( d["id"], d["instance"]["id"], tinkerbell, handler.host_state_dir, "flavor-runner.sh", ("-M", "/statedir/metadata"), {"PACKET_BOOTDEV_MAC": ""}, ) stamp = handler.statedir + "disks-partioned-image-extracted" metadata = handler.statedir + "metadata" cleanup = handler.statedir + "cleanup.sh" open(stamp, "w").close() handler.handle_provisioning(d) handlers.remove_statefile.assert_called() handlers.remove_statefile.call_args[0][0] == stamp assert not os.path.exists(stamp) assert not os.path.exists(cleanup) assert handlers.write_statefile.call_count == 2 assert handlers.write_statefile.call_args_list[0][0][0] == metadata assert handlers.write_statefile.call_args_list[1][0][0] == metadata assert os.path.exists(metadata) assert handler.run_osie.call_args_list == [call(*c), call(*c)]
def test_existence_of_loop_sh(mocked_run_osie): handler = mocked_run_osie cleanup = handler.statedir + "cleanup.sh" loop = handler.statedir + "loop.sh" metadata = handler.statedir + "metadata" stamp = handler.statedir + "disks-partioned-image-extracted" open(loop, "w").close() os.chmod(loop, 0o700) d = copy.deepcopy(cacher_provisioning) dpath.new(d, "instance/operating_system_version/os_slug", "freebsd_11_1") c = ( d["id"], d["instance"]["id"], tinkerbell, handler.host_state_dir, "flavor-runner.sh", ("-M", "/statedir/metadata"), {"PACKET_BOOTDEV_MAC": ""}, ) assert handler.handle_provisioning(d) assert os.path.exists(loop) assert not os.path.exists(stamp) assert not os.path.exists(cleanup) assert handlers.write_statefile.call_count == 2 assert handlers.write_statefile.call_args_list[0][0][0] == metadata assert handlers.write_statefile.call_args_list[1][0][0] == metadata assert os.path.exists(metadata) handler.run_osie.assert_called_with(*c)
def params_unprepare_from_saved(fields, copy_to_legacy=False): """ Unescape all section and param names for hyper params and configuration If copy_to_legacy is set then copy hyperparams and configuration data to the legacy location for the old clients """ for param_field in ("hyperparams", "configuration"): params = safe_get(fields, param_field) if params: unescaped_params = { ParameterKeyEscaper.unescape(key): { ParameterKeyEscaper.unescape(k): v for k, v in value.items() } if isinstance(value, dict) else value for key, value in params.items() } dpath.set(fields, param_field, unescaped_params) if copy_to_legacy: for new_params_field, old_params_field, use_sections in ( (f"hyperparams", "execution/parameters", True), (f"configuration", "execution/model_desc", False), ): legacy_params = _get_legacy_params( safe_get(fields, new_params_field), with_sections=use_sections ) if legacy_params: dpath.new( fields, old_params_field, {_get_full_param_name(p): p["value"] for p in legacy_params}, )
def build_definitions_context(definitions: Dict[str, DictNode], definitions_raw: Dict[str, List[Tuple[int, str]]]) -> \ Dict[str, Dict[str, Any]]: definitions_context: Dict[str, Dict[str, Any]] = {} definitions = deepcopy(definitions) # iterate on the files for file_path, resources in definitions.items(): for resource in resources: if resource.get("kind") == "List": resources.extend(item for item in resource.get("items", []) if item) resources.remove(resource) # iterate on the resources for resource in resources: if is_invalid_k8_definition(resource): continue resource_id = get_resource_id(resource) if not resource_id: continue start_line = resource["__startline__"] end_line = min(resource["__endline__"], len(definitions_raw[file_path])) first_line_index = 0 # skip empty lines while not str.strip(definitions_raw[file_path][first_line_index][1]): first_line_index += 1 # check if the file is a json file if str.strip(definitions_raw[file_path][first_line_index][1])[0] == "{": start_line += 1 end_line += 1 else: # add resource comments to definition lines current_line = str.strip(definitions_raw[file_path][start_line - 1][1]) while not current_line or current_line[0] == YAML_COMMENT_MARK: start_line -= 1 current_line = str.strip(definitions_raw[file_path][start_line - 1][1]) # remove next resource comments from definition lines current_line = str.strip(definitions_raw[file_path][end_line - 1][1]) while not current_line or current_line[0] == YAML_COMMENT_MARK: end_line -= 1 current_line = str.strip(definitions_raw[file_path][end_line - 1][1]) code_lines = definitions_raw[file_path][start_line - 1: end_line] dpath.new( definitions_context, [file_path, resource_id], {"start_line": start_line, "end_line": end_line, "code_lines": code_lines}, ) skipped_checks = get_skipped_checks(resource) dpath.new( definitions_context, [file_path, resource_id, "skipped_checks"], skipped_checks, ) return definitions_context
def params_prepare_for_save(fields: dict, previous_task: Task = None): """ If legacy hyper params or configuration is passed then replace the corresponding section in the new structure Escape all the section and param names for hyper params and configuration to make it mongo sage """ for old_params_field, new_params_field, default_section in ( ("execution/parameters", "hyperparams", hyperparams_default_section), ("execution/model_desc", "configuration", None), ): legacy_params = safe_get(fields, old_params_field) if legacy_params is None: continue if ( not safe_get(fields, new_params_field) and previous_task and previous_task[new_params_field] ): previous_data = previous_task.to_proper_dict().get(new_params_field) removed = _remove_legacy_params( previous_data, with_sections=default_section is not None ) if not legacy_params and not removed: # if we only need to delete legacy fields from the db # but they are not there then there is no point to proceed continue fields_update = {new_params_field: previous_data} params_unprepare_from_saved(fields_update) fields.update(fields_update) for full_name, value in legacy_params.items(): section, name = split_param_name(full_name, default_section) new_path = list(filter(None, (new_params_field, section, name))) new_param = dict(name=name, type=hyperparams_legacy_type, value=str(value)) if section is not None: new_param["section"] = section dpath.new(fields, new_path, new_param) dpath.delete(fields, old_params_field) for param_field in ("hyperparams", "configuration"): params = safe_get(fields, param_field) if params: escaped_params = { ParameterKeyEscaper.escape(key): { ParameterKeyEscaper.escape(k): v for k, v in value.items() } if isinstance(value, dict) else value for key, value in params.items() } dpath.set(fields, param_field, escaped_params)
def add(self, key: str, value: Any) -> Any: """Overwrite or add config value. Args: key: Key to set value: Value to add or update too Returns: Updated config """ dpath.new(self._config, key, value) self.log.debug(f"added config value [{key}] -> {value}") return self.sync()
def my_path(my_dictionary: dict = None, path=None, value=None): items = path.split('/') # if the last character is a digit if items[-1].isdigit(): items.pop() new_path = "/".join(items) # Check the element before the digit is already in the dictionary if dpath.search(my_dictionary, new_path): # Is it a list ? if isinstance(dpath.get(my_dictionary, new_path), list): dpath.new(my_dictionary, path, value) else: raise ValueError("The following entry can not be added: {}. " "This is not a list".format( my_dictionary[items[-2]])) # Not in the dictionary else: dpath.new(my_dictionary, new_path, []) dpath.new(my_dictionary, path, value) else: if dpath.search(my_dictionary, path): # Set the new value dpath.set(my_dictionary, path, value) else: dpath.new(my_dictionary, path, value) return my_dictionary
def test_provisioning(handler, path, value): d = copy.deepcopy(cacher_provisioning) hwid = d["id"] iid = d["instance"]["id"] c = ( hwid, iid, tinkerbell, handler.host_state_dir, "flavor-runner.sh", ("-M", "/statedir/metadata"), { "PACKET_BOOTDEV_MAC": "" }, ) if path: dpath.new(d, path, value) num_calls_write_statefile = 1 has_user_data = False if path == "instance/userdata" and value: has_user_data = True num_calls_write_statefile += 1 args = c[-2] + ("-u", "/statedir/userdata") c = c[:-2] + (args, ) + c[-1:] handler.handle_provisioning(d) handler.phone_home.assert_called_with({ "type": "provisioning.104.01", "body": "Device connected to DHCP system" }) handler.run_osie.assert_called_with(*c) handler.wipe.assert_not_called() assert handlers.write_statefile.call_count == num_calls_write_statefile assert ( handlers.write_statefile.call_args_list[0][0][0] == handler.statedir + "metadata") assert os.path.isfile(handler.statedir + "metadata") if has_user_data: assert os.path.isfile(handler.statedir + "userdata") assert (handlers.write_statefile.call_args_list[1][0][0] == handler.statedir + "userdata")
def set_preferences(call, company_id, req_model): # type: (APICall, str, SetPreferencesRequest) -> Dict assert isinstance(call, APICall) changes = req_model.preferences def invalid_key(_, key, __): if not isinstance(key, str): return True elif key.startswith("$") or "." in key: raise errors.bad_request.FieldsValueError( f"Key {key} is invalid. Keys cannot start with '$' or contain '.'." ) return True remap(changes, visit=invalid_key) base_preferences = get_user_preferences(call) new_preferences = deepcopy(base_preferences) for key, value in changes.items(): try: dpath.new(new_preferences, key, value, separator=".") except Exception: log.exception( 'invalid preferences update for user "{}": key=`%s`, value=`%s`', key, value, ) raise errors.bad_request.InvalidPreferencesUpdate(key=key, value=value) if new_preferences == base_preferences: updated, fields = 0, {} else: with translate_errors_context("updating user preferences"): updated = User.objects(id=call.identity.user, company=company_id).update( upsert=False, preferences=dumps(new_preferences)) return { "updated": updated, "fields": { "preferences": new_preferences } if updated else {}, }
def test_provisioning_mismatch_preinstalled(handler, path, value): d = copy.deepcopy(cacher_provisioning) dpath.new(d, path, value) c = ( d["id"], d["instance"]["id"], tinkerbell, handler.host_state_dir, "flavor-runner.sh", ("-M", "/statedir/metadata"), { "PACKET_BOOTDEV_MAC": "" }, ) if path == "instance/userdata" and value: args = c[-2] + ("-u", "/statedir/userdata") c = c[:-2] + (args, ) + c[-1:] handler.handle_provisioning(d) handler.phone_home.assert_not_called() handler.run_osie.assert_called_with(*c) handler.wipe.assert_called_with(d) metadata = handler.statedir + "metadata" cleanup = handler.statedir + "cleanup.sh" userdata = handler.statedir + "userdata" assert os.path.isfile(cleanup) assert stat.S_IMODE(os.stat(cleanup).st_mode) == 0o700 assert open(cleanup).read() == "#!/usr/bin/env sh\nreboot\n" assert os.path.isfile(metadata) assert handlers.write_statefile.call_args_list[0][0][0] == metadata assert handlers.write_statefile.call_args_list[-1][0][0] == cleanup handlers.remove_statefile.assert_not_called() write_satefile_count = 2 if path == "instance/userdata" and value: assert os.path.isfile(userdata) write_satefile_count += 1 assert handlers.write_statefile.call_args_list[1][0][0] == userdata assert handlers.write_statefile.call_count == write_satefile_count
def _upgrade_task_data(task_data: dict): for old_param_field, new_param_field, default_section in ( ("execution/parameters", "hyperparams", hyperparams_default_section), ("execution/model_desc", "configuration", None), ): legacy = safe_get(task_data, old_param_field) if not legacy: continue for full_name, value in legacy.items(): section, name = split_param_name(full_name, default_section) new_path = list(filter(None, (new_param_field, section, name))) if not safe_get(task_data, new_path): new_param = dict( name=name, type=hyperparams_legacy_type, value=str(value) ) if section is not None: new_param["section"] = section dpath.new(task_data, new_path, new_param) dpath.delete(task_data, old_param_field)
def merge_projection_result(result): for ref_field_name, data in ref_projection.items(): res = data.get('res') if not res: self._expand_reference_fields(cls, result, [ref_field_name]) continue ref_ids = self._search(cls, result, ref_field_name, only_values=False) if not ref_ids: continue for path, value in ref_ids: obj = res.get(value) or {'id': value} dpath.new(result, path, obj, separator='.') # any reference field not projected should be expanded do_expand_reference_ids(result, skip_fields=list(ref_projection))
def _assign_definition_value(self, var_name, var_value, var_assignments): assignment_regex = self._generate_var_evaluation_regex(var_name) var_file = var_assignments['var_file'] for (assignment_file, assignments) in var_assignments['definitions'].items(): # Save evaluation information in context for assignment_obj in assignments: definition_path = assignment_obj.get('definition_path') entry_expression = assignment_obj.get('definition_expression') definition_name = assignment_obj.get('definition_name') context_path, _ = self._extract_context_path(definition_path) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/var_file', var_file) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/value', var_value) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/definitions', assignments) evaluated_value = str(var_value) evaluated_definition = re.sub(assignment_regex, evaluated_value, entry_expression) dpath.set(self.tf_definitions[assignment_file], definition_path, evaluated_definition) self.logger.debug( f'Evaluated definition {definition_name} in file {assignment_file}: default value of variable {var_file}: ' f'{var_name} to "{evaluated_value}"')
def _assign_definition_value(self, var_name, var_value, var_assignments): assignment_regex = self._generate_var_evaluation_regex(var_name) var_file = var_assignments['var_file'] var_value_string = str(var_value) for (assignment_file, assignments) in var_assignments['definitions'].items(): # Save evaluation information in context for assignment_obj in assignments: definition_path = assignment_obj.get('definition_path') entry_expression = assignment_obj.get('definition_expression') definition_name = assignment_obj.get('definition_name') context_path, _ = self._extract_context_path(definition_path) if assignment_file in self.definitions_context.keys(): dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/var_file', var_file) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/value', var_value) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/definitions', assignments) if self._is_variable_only_expression(assignment_regex, entry_expression): # Preserve the original type of the variable if not part of a composite expression evaluated_definition = var_value else: evaluated_definition = re.sub(assignment_regex, var_value_string, entry_expression) dpath.set(self.tf_definitions[assignment_file], definition_path, evaluated_definition) self.logger.debug( f'Evaluated definition {definition_name} in file {assignment_file}: default value of variable {var_file}: ' f'{var_name} to "{var_value_string}"')
def add_result(self, result_id, result): try: registered = self._registers.get(result_id, None) if registered is None: raise FrklException( msg= "Result for id '{}' not registered, this is most likely a bug." .format(result_id)) value_template = registered.get("value", None) if value_template is not None: new_value = replace_strings_in_obj( value_template, replacement_dict={"__result__": result}, jinja_env=DEFAULT_RUN_CONFIG_JINJA_ENV, ) else: new_value = result target = registered.get("target", None) if target is None: if not isinstance(result, Mapping): raise FrklException( msg="Can't merge result id '{}'".format(result_id), reason= "Value for result-id '{}' not a mapping, and no 'target' provided.", solution= "Either provide a 'target' value, or use the 'value' template to convert the result.", ) dict_merge(self._result, new_value, copy_dct=False) else: temp = {} dpath.new(temp, target, new_value, separator=".") dict_merge(self._result, temp, copy_dct=False) except (Exception) as e: log.error("Could not register result '{}': {}".format( result_id, e))
def parse_section_title(self, cell, current_section=None): if not isinstance(cell.internal_value, str): raise SheetParsingError( "Enable to parse summary: Unexpected value in cell '{}'". format(cell.coordinate)) description = ''.join(cell.internal_value.split('.')[1:]).strip() key = slugify(description, stopwords=True) path = f"subparams/{current_section}/subparams/{key}" if current_section else f"subparams/{key}" if dpath.search(self.sections, path): raise SheetParsingError( "Name collision: section '{}' alredy exists.".format(path)) dpath.new(self.sections, path, { 'description': description, 'metadata': { 'order': [] } }) # Keep track of the order order_path = f'subparams/{current_section}/metadata/order' if current_section else 'metadata/order' dpath.get(self.sections, order_path).append(key) return path
def _assign_definition_value(self, definition_type, var_name, var_value, var_assignments): """ assigns var_value to variable var_name in tf_definitions :param definition_type: the entity's block type :param var_name: variable name :param var_value: variable value :param var_assignments: variable assignments """ assignment_regex = self._generate_evaluation_regex( definition_type, var_name) var_file = var_assignments['var_file'] var_value_string = str(var_value) for (assignment_file, assignments) in var_assignments['definitions'].items(): # Save evaluation information in context for assignment_obj in assignments: definition_path = assignment_obj.get('definition_path') entry_expression = assignment_obj.get('definition_expression') definition_name = assignment_obj.get('definition_name') if not isinstance(entry_expression, str): # Example of unsupported evaluation: # cidr_blocks = local.ip_ranges.ipv4Prefixes[*].prefix logging.info( f'Ran into a complex evaluation which isn\'t supported yet, on {assignment_file}' ) continue context_path, _ = self.extract_context_path(definition_path) if assignment_file in self.definitions_context.keys(): dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/var_file', var_file) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/value', var_value) dpath.new(self.definitions_context[assignment_file], f'evaluations/{var_name}/definitions', assignments) if self._is_variable_only_expression(assignment_regex, entry_expression): # Preserve the original type of the variable if not part of a composite expression evaluated_definition = var_value else: evaluated_definition = re.sub(assignment_regex, re.escape(var_value_string), entry_expression) dpath.set(self.tf_definitions[assignment_file], definition_path, evaluated_definition) self.logger.debug( f'Evaluated definition {definition_name} in file {assignment_file}: default value of variable {var_file}: ' f'{var_name} to "{var_value_string}"')
def build_openAPI_specification(api_data): tax_benefit_system = api_data['tax_benefit_system'] file = open(OPEN_API_CONFIG_FILE, 'r') spec = yaml.safe_load(file) country_package_name = api_data['country_package_metadata']['name'].title() dpath.new(spec, 'info/title', spec['info']['title'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name)) dpath.new(spec, 'info/description', spec['info']['description'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name)) dpath.new(spec, 'info/version', api_data['country_package_metadata']['version']) for entity in tax_benefit_system.entities: name = entity.key.title() spec['definitions'][name] = get_entity_json_schema(entity, tax_benefit_system) situation_schema = get_situation_json_schema(tax_benefit_system) dpath.new(spec, 'definitions/SituationInput', situation_schema) dpath.new(spec, 'definitions/SituationOutput', situation_schema.copy()) dpath.new(spec, 'definitions/Trace/properties/entitiesDescription/properties', { entity.plural: {'type': 'array', 'items': {"type": "string"}} for entity in tax_benefit_system.entities }) # Get example from the served tax benefist system if tax_benefit_system.open_api_config.get('parameter_example'): parameter_id = tax_benefit_system.open_api_config['parameter_example'] parameter_path = parameter_id.replace('.', '/') parameter_example = api_data['parameters'][parameter_path] else: parameter_example = next(iter(api_data['parameters'].values())) dpath.new(spec, 'definitions/Parameter/example', parameter_example) if tax_benefit_system.open_api_config.get('variable_example'): variable_example = api_data['variables'][tax_benefit_system.open_api_config['variable_example']] else: variable_example = next(iter(api_data['variables'].values())) dpath.new(spec, 'definitions/Variable/example', variable_example) if tax_benefit_system.open_api_config.get('simulation_example'): simulation_example = tax_benefit_system.open_api_config['simulation_example'] dpath.new(spec, 'definitions/SituationInput/example', simulation_example) dpath.new(spec, 'definitions/SituationOutput/example', handlers.calculate(tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects dpath.new(spec, 'definitions/Trace/example', handlers.trace(tax_benefit_system, simulation_example)) else: message = "No simulation example has been defined for this tax and benefit system. If you are the maintainer of {}, you can define an example by following this documentation: https://openfisca.org/doc/openfisca-web-api/config-openapi.html".format(country_package_name) dpath.new(spec, 'definitions/SituationInput/example', message) dpath.new(spec, 'definitions/SituationOutput/example', message) dpath.new(spec, 'definitions/Trace/example', message) return spec
def admin_request_body_field(context, field, value): dpath.new(context.obj, field, value)
def set(self, path, value): if (path == '/'): return False return dpath.new(self.info, path, value)
def build_openAPI_specification(api_data): tax_benefit_system = api_data['tax_benefit_system'] file = open(OPEN_API_CONFIG_FILE, 'r') spec = yaml.load(file) country_package_name = api_data['country_package_metadata']['name'].title() dpath.new( spec, 'info/title', spec['info']['title'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name)) dpath.new( spec, 'info/description', spec['info']['description'].replace("{COUNTRY_PACKAGE_NAME}", country_package_name)) dpath.new(spec, 'info/version', api_data['country_package_metadata']['version']) for entity in tax_benefit_system.entities: name = entity.key.title() spec['definitions'][name] = get_entity_json_schema( entity, tax_benefit_system) situation_schema = get_situation_json_schema(tax_benefit_system) dpath.new(spec, 'definitions/SituationInput', situation_schema) dpath.new(spec, 'definitions/SituationOutput', situation_schema.copy()) dpath.new( spec, 'definitions/Trace/properties/entitiesDescription/properties', { entity.plural: { 'type': 'array', 'items': { "type": "string" } } for entity in tax_benefit_system.entities }) # Get example from the served tax benefist system if tax_benefit_system.open_api_config.get('parameter_example'): parameter_id = tax_benefit_system.open_api_config['parameter_example'] parameter_path = parameter_id.replace('.', '/') parameter_example = api_data['parameters'][parameter_path] else: parameter_example = next(iter(api_data['parameters'].values())) dpath.new(spec, 'definitions/Parameter/example', parameter_example) if tax_benefit_system.open_api_config.get('variable_example'): variable_example = api_data['variables'][ tax_benefit_system.open_api_config['variable_example']] else: variable_example = next(iter(api_data['variables'].values())) dpath.new(spec, 'definitions/Variable/example', variable_example) if tax_benefit_system.open_api_config.get('simulation_example'): simulation_example = tax_benefit_system.open_api_config[ 'simulation_example'] dpath.new(spec, 'definitions/SituationInput/example', simulation_example) dpath.new( spec, 'definitions/SituationOutput/example', handlers.calculate( tax_benefit_system, deepcopy(simulation_example))) # calculate has side-effects dpath.new(spec, 'definitions/Trace/example', handlers.trace(tax_benefit_system, simulation_example)) else: message = "No simulation example has been defined for this tax and benefit system. If you are the maintainer of {}, you can define an example by following this documentation: https://openfisca.org/doc/openfisca-web-api/config-openapi.html".format( country_package_name) dpath.new(spec, 'definitions/SituationInput/example', message) dpath.new(spec, 'definitions/SituationOutput/example', message) dpath.new(spec, 'definitions/Trace/example', message) return spec
def __init__(self, *args, **kwargs): self.requireComplete=kwargs.pop('requireComplete', True) kws_ = {} for k, v in kwargs.items(): dpath.new( kws_, py_index_to_pdict(k), v, separator='.' ) super().__init__(*args, **kws_)
def execute_postponed_actions(context, is_data: bool = True, actions_switcher: dict = None): """ Execute postponed actions :param actions_switcher: the automaton list of actions which can be postponed :param context: the current context :param is_data: boolean, True means set only data, False means execute actions (use models) :return: None """ log.debug("postponed_action") if is_data: # Do settings log.debug("is data statement") key_list = set(ATTRIBUTE_LIST).intersection( context.pre_conditions["postponed"].keys()) for key in key_list: log.debug("Key : {}".format(str(key))) while context.pre_conditions["postponed"][key]: log.debug("Context.pre_conditions[postponed][key]: {} ".format( context.pre_conditions["postponed"][key])) elem = context.pre_conditions["postponed"][key].pop(0) log.debug("elem contains: {}".format(elem)) try: # Check the path exist if dpath.search(context.pre_conditions[key], elem["path"]): dpath.set(context.pre_conditions[key], elem["path"], elem["value"]) else: # Create a new entry dpath.new(context.pre_conditions[key], elem["path"], elem["value"]) except AssertionError as assertion: log.error("Update data failed.\n '{}'".format( assertion.args[0])) raise_exception( AssertionError, "Update data failed.\n '{}'".format(assertion.args[0]), context.evidence_folder) log.debug("pre_conditions : {}".format( str(context.pre_conditions[key]))) else: # Do execute steps log.debug("else statement") postponed_actions = deepcopy( context.pre_conditions["postponed"]["execution"]) context.pre_conditions["postponed"]["execution"].clear() for index, action in enumerate(postponed_actions): log.debug("Index: {}, action: {}".format(index, action)) if isinstance(action, str): context.execute_steps(action) elif isinstance(action, tuple) and len(action) == 2: log.debug("action switcher: {}".format(action)) actions_switcher[action[0]](**action[1]) sleep(0.5) else: raise Exception("Unknown action to process.\n" "Get '{}'".format(repr(action))) log.debug("End of postponed_action ")