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()
case_insensitive = True
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 print(self, tab=''):
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]
def save(self, filename):
63	def save(self,filename):
64		with open(filename,"w") as f:
65			f.write(self.print())
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