fennol.utils.input_parser
1import re 2from .atomic_units import AtomicUnits as au 3_separators=" |,|=|\t|\n" 4_comment_chars=["#","!"] 5_true_repr=["true","yes",".true."] 6_false_repr=["false","no",".false."] 7 8class InputFile(dict): 9 case_insensitive=True 10 def get(self, path, default = None): 11 if InputFile.case_insensitive: 12 path=path.lower() 13 keys = path.split("/") 14 val = None 15 for key in keys: 16 if isinstance(val,InputFile): 17 val = val.get(key, default=None) 18 else: 19 val = dict.get(self, key, None) 20 21 if val is None: 22 return default 23 24 return val 25 26 def store(self, path, value): 27 if InputFile.case_insensitive: 28 path=path.lower() 29 keys = path.split("/") 30 child = self.get(keys[0],default=None) 31 if isinstance(child,InputFile): 32 if len(keys) == 1: 33 print("Warning: overriding a sub-dictionary!") 34 self[keys[0]]=value 35 return 1 36 else: 37 child.store("/".join(keys[1:]),value) 38 else: 39 if len(keys) == 1: 40 self[keys[0]]=value 41 return 0 42 else: 43 if child is None: 44 self[keys[0]]=InputFile() 45 self[keys[0]].store("/".join(keys[1:]),value) 46 else: 47 print("Error: hit a leaf before the end of path!") 48 return -1 49 50 51 def print(self,tab=""): 52 string = "" 53 for p_id, p_info in self.items(): 54 string += tab+p_id 55 val=self.get(p_id) 56 if isinstance(val,InputFile): 57 string += "{\n" + val.print(tab=tab+" ") +"\n"+tab+"}\n\n" 58 else: 59 string += " = "+str(val)+"\n" 60 return string[:-1] 61 62 def save(self,filename): 63 with open(filename,"w") as f: 64 f.write(self.print()) 65 66 def __str__(self): 67 return self.print() 68 69 70def parse_input(input_file): 71# parse an input file and return a nested dictionary 72# containing the categories, keys and values 73 f=open(input_file,'r') 74 struct=InputFile() 75 path=[] 76 for line in f: 77 #remove all after comment character 78 for comment_char in _comment_chars: 79 index=line.find(comment_char) 80 if index >= 0: 81 line=line[:index] 82 83 #split line using defined separators 84 parsed_line=re.split(_separators, 85 line.strip()) 86 87 #remove empty strings 88 parsed_line=[x for x in parsed_line if x] 89 #skip blank lines 90 if not parsed_line: 91 continue 92 #print(parsed_line) 93 94 word0 = parsed_line[0].lower() 95 cat_fields=''.join(parsed_line) 96 #check if beginning of a category 97 if cat_fields.endswith("{"): 98 path.append(cat_fields[:-1]) 99 continue 100 if cat_fields.startswith("&"): 101 path.append(cat_fields[1:]) 102 continue 103 if cat_fields.endswith("{}"): 104 struct.store("/".join("path")+"/"+cat_fields[1:-2] 105 ,InputFile()) 106 continue 107 108 #print(current_category) 109 #if not path: 110 # print("Error: line not recognized!") 111 # return None 112 # else: #check if end of a category 113 if (cat_fields[0] in "}/") or ("&end" in cat_fields): 114 del path[-1] 115 continue 116 117 word0, unit=_get_unit_from_key(word0) 118 val=None 119 if len(parsed_line) == 1: 120 val=True # keyword only => store True 121 elif len(parsed_line) == 2: 122 val=string_to_true_type(parsed_line[1],unit) 123 else: 124 #analyze parsed line 125 val=[] 126 for word in parsed_line[1:]: 127 val.append(string_to_true_type(word,unit)) 128 struct.store("/".join(path+[word0]),val) 129 130 f.close() 131 return struct 132 133def string_to_true_type(word,unit=None): 134 if unit is not None: 135 return float(word)/unit 136 137 try: 138 val=int(word) 139 except ValueError: 140 try: 141 val=float(word) 142 except ValueError: 143 if word.lower() in _true_repr: 144 val=True 145 elif word.lower() in _false_repr: 146 val=False 147 else: 148 val=word 149 return val 150 151def _get_unit_from_key(word): 152 unit_start=max(word.find("{"),word.find("[")) 153 n=len(word) 154 if unit_start<0: 155 key=word 156 unit=None 157 elif unit_start==0: 158 print("Error: Field '"+str(word)+"' must not start with '{' or '[' !") 159 raise ValueError 160 else: 161 if word[unit_start] == "{": 162 end_bracket="}" 163 else: 164 end_bracket="]" 165 key=word[:unit_start] 166 if word[n-1] != end_bracket: 167 print("Error: wrong unit specification in field '"+str(word)+"' !") 168 raise ValueError 169 170 if n-unit_start-2 < 0 : 171 unit=1. 172 else : 173 unit=au.get_multiplier(word[unit_start+1:-1]) 174 #print(key+" unit= "+str(unit)) 175 return key, unit
class
InputFile(builtins.dict):
9class InputFile(dict): 10 case_insensitive=True 11 def get(self, path, default = None): 12 if InputFile.case_insensitive: 13 path=path.lower() 14 keys = path.split("/") 15 val = None 16 for key in keys: 17 if isinstance(val,InputFile): 18 val = val.get(key, default=None) 19 else: 20 val = dict.get(self, key, None) 21 22 if val is None: 23 return default 24 25 return val 26 27 def store(self, path, value): 28 if InputFile.case_insensitive: 29 path=path.lower() 30 keys = path.split("/") 31 child = self.get(keys[0],default=None) 32 if isinstance(child,InputFile): 33 if len(keys) == 1: 34 print("Warning: overriding a sub-dictionary!") 35 self[keys[0]]=value 36 return 1 37 else: 38 child.store("/".join(keys[1:]),value) 39 else: 40 if len(keys) == 1: 41 self[keys[0]]=value 42 return 0 43 else: 44 if child is None: 45 self[keys[0]]=InputFile() 46 self[keys[0]].store("/".join(keys[1:]),value) 47 else: 48 print("Error: hit a leaf before the end of path!") 49 return -1 50 51 52 def print(self,tab=""): 53 string = "" 54 for p_id, p_info in self.items(): 55 string += tab+p_id 56 val=self.get(p_id) 57 if isinstance(val,InputFile): 58 string += "{\n" + val.print(tab=tab+" ") +"\n"+tab+"}\n\n" 59 else: 60 string += " = "+str(val)+"\n" 61 return string[:-1] 62 63 def save(self,filename): 64 with open(filename,"w") as f: 65 f.write(self.print()) 66 67 def __str__(self): 68 return self.print()
def
get(self, path, default=None):
11 def get(self, path, default = None): 12 if InputFile.case_insensitive: 13 path=path.lower() 14 keys = path.split("/") 15 val = None 16 for key in keys: 17 if isinstance(val,InputFile): 18 val = val.get(key, default=None) 19 else: 20 val = dict.get(self, key, None) 21 22 if val is None: 23 return default 24 25 return val
Return the value for key if key is in the dictionary, else default.
def
store(self, path, value):
27 def store(self, path, value): 28 if InputFile.case_insensitive: 29 path=path.lower() 30 keys = path.split("/") 31 child = self.get(keys[0],default=None) 32 if isinstance(child,InputFile): 33 if len(keys) == 1: 34 print("Warning: overriding a sub-dictionary!") 35 self[keys[0]]=value 36 return 1 37 else: 38 child.store("/".join(keys[1:]),value) 39 else: 40 if len(keys) == 1: 41 self[keys[0]]=value 42 return 0 43 else: 44 if child is None: 45 self[keys[0]]=InputFile() 46 self[keys[0]].store("/".join(keys[1:]),value) 47 else: 48 print("Error: hit a leaf before the end of path!") 49 return -1
def
parse_input(input_file):
71def parse_input(input_file): 72# parse an input file and return a nested dictionary 73# containing the categories, keys and values 74 f=open(input_file,'r') 75 struct=InputFile() 76 path=[] 77 for line in f: 78 #remove all after comment character 79 for comment_char in _comment_chars: 80 index=line.find(comment_char) 81 if index >= 0: 82 line=line[:index] 83 84 #split line using defined separators 85 parsed_line=re.split(_separators, 86 line.strip()) 87 88 #remove empty strings 89 parsed_line=[x for x in parsed_line if x] 90 #skip blank lines 91 if not parsed_line: 92 continue 93 #print(parsed_line) 94 95 word0 = parsed_line[0].lower() 96 cat_fields=''.join(parsed_line) 97 #check if beginning of a category 98 if cat_fields.endswith("{"): 99 path.append(cat_fields[:-1]) 100 continue 101 if cat_fields.startswith("&"): 102 path.append(cat_fields[1:]) 103 continue 104 if cat_fields.endswith("{}"): 105 struct.store("/".join("path")+"/"+cat_fields[1:-2] 106 ,InputFile()) 107 continue 108 109 #print(current_category) 110 #if not path: 111 # print("Error: line not recognized!") 112 # return None 113 # else: #check if end of a category 114 if (cat_fields[0] in "}/") or ("&end" in cat_fields): 115 del path[-1] 116 continue 117 118 word0, unit=_get_unit_from_key(word0) 119 val=None 120 if len(parsed_line) == 1: 121 val=True # keyword only => store True 122 elif len(parsed_line) == 2: 123 val=string_to_true_type(parsed_line[1],unit) 124 else: 125 #analyze parsed line 126 val=[] 127 for word in parsed_line[1:]: 128 val.append(string_to_true_type(word,unit)) 129 struct.store("/".join(path+[word0]),val) 130 131 f.close() 132 return struct
def
string_to_true_type(word, unit=None):
134def string_to_true_type(word,unit=None): 135 if unit is not None: 136 return float(word)/unit 137 138 try: 139 val=int(word) 140 except ValueError: 141 try: 142 val=float(word) 143 except ValueError: 144 if word.lower() in _true_repr: 145 val=True 146 elif word.lower() in _false_repr: 147 val=False 148 else: 149 val=word 150 return val