diff --git a/JsonPreprocessor/CJsonPreprocessor.py b/JsonPreprocessor/CJsonPreprocessor.py index ca536060..08ca1abb 100644 --- a/JsonPreprocessor/CJsonPreprocessor.py +++ b/JsonPreprocessor/CJsonPreprocessor.py @@ -176,6 +176,10 @@ def __init__(self, syntax: CSyntaxType = CSyntaxType.python , currentCfg : dict Internally used to aggregate imported json files. """ + import builtins + import keyword + self.lDataTypes = [name for name, value in vars(builtins).items() if isinstance(value, type)] + self.lDataTypes.append(keyword.kwlist) self.lImportedFiles = [] self.recursive_level = 0 self.syntax = syntax @@ -344,6 +348,31 @@ def replacer(match): return sContentCleaned + def __checkParamName(self, sInput: str) -> str: + """ + Checks a parameter name, in case the name is conflict with Python keywords, the temporary prefix + will be added to avoid any potential issues. This temporary prefix is removed when updating returned + Json object. + +**Args:** + + **sInput** (*string*) + +**Returns:** + + **sInput** (*string*) + """ + + pattern = "\${\s*([0-9A-Za-z_]+[0-9A-Za-z\.\-_]*)\s*}" + lParams = re.findall(pattern, sInput) + for param in lParams: + if "." not in param and param in self.lDataTypes: + sInput = re.sub(param, "JPavoidDataType_" + param, sInput, count=1) + if "." in param and "JPavoidDataType_" + param.split('.')[0] in globals(): + sInput = re.sub(param, "JPavoidDataType_" + param, sInput, count=1) + return sInput + + def __nestedParamHandler(self, sInputStr : str, bKey = False) -> list: ''' This method handles nested variables in parameter names or values. Variable syntax is ${Variable_Name}. @@ -503,6 +532,8 @@ def __jsonUpdated(k, v, oJson, bNested, keyNested = ''): except: raise Exception(f"Could not set variable '{k}' with value '{v}'!") + if "JPavoidDataType_" in k: + k = re.sub("JPavoidDataType_", "", k) if isinstance(v, str): sExec = "oJson['" + k.split('[', 1)[0] + "'][" + k.split('[', 1)[1] + " = \"" + v + "\"" else: @@ -512,15 +543,20 @@ def __jsonUpdated(k, v, oJson, bNested, keyNested = ''): except: pass else: + if "JPavoidDataType_" in k: + k = re.sub("JPavoidDataType_", "", k) oJson[k] = v else: if bNested: + if "JPavoidDataType_" in k: + k = re.sub("JPavoidDataType_", "", k) oJson[k] = v - if bool(self.currentCfg) and not recursive: for k, v in self.currentCfg.items(): + if k in self.lDataTypes: + k = "JPavoidDataType_" + k globals().update({k:v}) tmpJson = copy.deepcopy(oJson) @@ -528,8 +564,13 @@ def __jsonUpdated(k, v, oJson, bNested, keyNested = ''): keyNested = '' if re.match('.*\${\s*', k.lower()): keyNested = k + pattern = "\${\s*[0-9A-Za-z_]+[0-9A-Za-z\.\-_]*\s*}(\[\s*.+\s*\])*" if re.match("str\(\s*\${.+", k.lower()): - k = re.sub("str\(\s*(\${.+)\s*\)", "\\1", k) + k = re.sub("str\(\s*(" + pattern + ")\s*\)", "\\1", k) + if len(re.findall(pattern, k.lower())) > 1 or k.count('{') != k.count('}'): + raise Exception(f"Could not overwrite parameter {k} due to wrong format.\n \ + Please check key '{k}' in config file!!!") + k = self.__checkParamName(k) keyAfterProcessed = self.__nestedParamHandler(k, bKey=True) k = re.sub('^\s*\${\s*(.*?)\s*}', '\\1', keyAfterProcessed[0]) @@ -545,6 +586,7 @@ def __jsonUpdated(k, v, oJson, bNested, keyNested = ''): if re.match("str\(\s*\${.+", item.lower()): item = re.sub("str\(\s*(\${.+)\s*\)", "\\1", item) bStringValue = True + item = self.__checkParamName(item) itemAfterProcessed = self.__nestedParamHandler(item) tmpItemAfterProcessed = re.sub('\${\s*(.*?)\s*}', '\\1', itemAfterProcessed[0]) sExec = "value = " + tmpItemAfterProcessed if isinstance(tmpItemAfterProcessed, str) else \ @@ -570,6 +612,7 @@ def __jsonUpdated(k, v, oJson, bNested, keyNested = ''): if re.search("(str\(\s*" + pattern + "\))", v.lower()): v = re.sub("str\(\s*(" + pattern + ")\s*\)", "\\1", v) bStringValue = True + v = self.__checkParamName(v) valueAfterProcessed = self.__nestedParamHandler(v) for valueProcessed in valueAfterProcessed: tmpValueAfterProcessed = re.sub('\\${\s*(.*?)\s*}', '\\1', valueProcessed) @@ -617,10 +660,14 @@ def __checkAndUpdateKeyValue(self, sInputStr: str) -> str: for nestedParam in lNestedParam: self.lNestedParams.append(nestedParam[0]) sInputStr = re.sub("(" + pattern + ")", "str(\\1)", sInputStr) - elif re.search(pattern, sInputStr.lower()): + elif re.search("^\s*" + pattern + "\s*\]*\}*,*\s*$", sInputStr.lower()): sInputStr = re.sub("(" + pattern + ")", "\"\\1\"", sInputStr) nestedParam = re.sub("^\s*\"(.+)\"\s*.*$", "\\1", sInputStr) self.lNestedParams.append(nestedParam) + else: + if len(re.findall(pattern, sInputStr.lower()))>1: + raise Exception(f"Key name or value is a mix of nested parameters and hard coded parts. \n \ + The entire expression {sInputStr.strip()} must be enclosed in quotes") sOutput = sInputStr return sOutput @@ -784,6 +831,8 @@ def __handleListElements(sInput : str) -> str: if masterFile: for k, v in oJson.items(): + if k in self.lDataTypes: + k = "JPavoidDataType_" + k globals().update({k:v}) oJson, bNested = self.__updateAndReplaceNestedParam(oJson) for k, v in self.dUpdatedParams.items(): @@ -804,6 +853,7 @@ def __handleListElements(sInput : str) -> str: # Checking availability of nested parameters before updating and replacing. for param in self.lNestedParams: + param = self.__checkParamName(param) parseNestedParam = self.__nestedParamHandler(param) tmpParseNestedParam = re.sub('\\${\s*(.*?)\s*}', '\\1', parseNestedParam[0]) sExec = "value = " + tmpParseNestedParam if isinstance(tmpParseNestedParam, str) else \