def parse_variables_mapping(variables_mapping): """ eval each prepared variable and function in variables_mapping. Args: variables_mapping (dict): { "varA": LazyString(123$varB), "varB": LazyString(456$varC), "varC": LazyString(${sum_two($a, $b)}), "a": 1, "b": 2, "c": {"key": LazyString($b)}, "d": [LazyString($a), 3] } Returns: dict: parsed variables_mapping should not contain any variable or function. { "varA": "1234563", "varB": "4563", "varC": "3", "a": 1, "b": 2, "c": {"key": 2}, "d": [1, 3] } """ run_times = 0 parsed_variables_mapping = {} while len(parsed_variables_mapping) != len(variables_mapping): for var_name in variables_mapping: run_times += 1 if run_times > len(variables_mapping) * 4: not_found_variables = { key: variables_mapping[key] for key in variables_mapping if key not in parsed_variables_mapping } raise exceptions.VariableNotFound(not_found_variables) if var_name in parsed_variables_mapping: continue value = variables_mapping[var_name] variables = extract_variables(value) # check if reference variable itself if var_name in variables: # e.g. # var_name = "token" # variables_mapping = {"token": LazyString($token)} # var_name = "key" # variables_mapping = {"key": [LazyString($key), 2]} raise exceptions.VariableNotFound(var_name) if variables: # reference other variable, or function call with other variable # e.g. {"varA": "123$varB", "varB": "456$varC"} # e.g. {"varC": "${sum_two($a, $b)}"} if any([ _var_name not in parsed_variables_mapping for _var_name in variables ]): # reference variable not parsed continue parsed_value = parse_lazy_data(value, parsed_variables_mapping) parsed_variables_mapping[var_name] = parsed_value return parsed_variables_mapping
def __parse(self, raw_string): """ parse raw string, replace function and variable with {} Args: raw_string(str): string with functions or varialbes e.g. "ABC${func2($a, $b)}DE$c" Returns: string: "ABC{}DE{}" args: ["${func2($a, $b)}", "$c"] """ self._args = [] def escape_braces(origin_string): return origin_string.replace("{", "{{").replace("}", "}}") try: match_start_position = raw_string.index("$", 0) begin_string = raw_string[0:match_start_position] self._string = escape_braces(begin_string) except ValueError: self._string = escape_braces(raw_string) return while match_start_position < len(raw_string): # Notice: notation priority # $$ > ${func($a, $b)} > $var # search $$ dollar_match = dolloar_regex_compile.match(raw_string, match_start_position) if dollar_match: match_start_position = dollar_match.end() self._string += "$" continue # search function like ${func($a, $b)} func_match = function_regex_compile.match(raw_string, match_start_position) if func_match: function_meta = {"func_name": func_match.group(1)} function_meta.update(parse_function_params( func_match.group(2))) lazy_func = LazyFunction(function_meta, self.functions_mapping, self.check_variables_set) self._args.append(lazy_func) match_start_position = func_match.end() self._string += "{}" continue # search variable like ${var} or $var var_match = variable_regex_compile.match(raw_string, match_start_position) if var_match: var_name = var_match.group(1) or var_match.group(2) # check if any variable undefined in check_variables_set if var_name not in self.check_variables_set: raise exceptions.VariableNotFound(var_name) self._args.append(var_name) match_start_position = var_match.end() self._string += "{}" continue curr_position = match_start_position try: # find next $ location match_start_position = raw_string.index("$", curr_position + 1) remain_string = raw_string[curr_position:match_start_position] except ValueError: remain_string = raw_string[curr_position:] # break while loop match_start_position = len(raw_string) self._string += escape_braces(remain_string)