77
88"""
99
10- import yaml
1110import json
11+ import yaml
12+
1213from .. import format
14+ from ..info import FORMAT_VERSION
1315from . import xmlparser
1416
15- # FIX ME: Version should not be hardcoded here. Import from odML module after
16- # fixing the circular imports issue.
17- odml_version = '1'
18-
1917allowed_parsers = ['ODML' , 'XML' , 'YAML' , 'JSON' ]
2018
2119
20+ class ParserException (Exception ):
21+ pass
22+
23+
2224class ODMLWriter :
23- '''
25+ """
2426 A generic odML document writer, for XML, YAML and JSON.
2527
2628 Usage:
2729 xml_writer = ODMLWriter(parser='XML')
2830 xml_writer.write_file(odml_document, filepath)
29- '''
31+ """
3032
3133 def __init__ (self , parser = 'XML' ):
3234 self .doc = None # odML document
@@ -55,7 +57,6 @@ def to_dict(self, odml_document):
5557 self .parsed_doc = parsed_doc
5658
5759 def get_sections (self , section_list ):
58-
5960 section_seq = []
6061
6162 for section in section_list :
@@ -81,7 +82,6 @@ def get_sections(self, section_list):
8182 return section_seq
8283
8384 def get_properties (self , props_list ):
84-
8585 props_seq = []
8686
8787 for prop in props_list :
@@ -100,7 +100,7 @@ def get_properties(self, props_list):
100100 prop_dict [attr ] = t
101101
102102 props_seq .append (prop_dict )
103-
103+
104104 return props_seq
105105
106106 def get_values (self , value_list ):
@@ -122,6 +122,17 @@ def get_values(self, value_list):
122122 return value_seq
123123
124124 def write_file (self , odml_document , filename ):
125+ # Write document only if it does not contain validation errors.
126+ from ..validation import Validation # disgusting import problems
127+ validation = Validation (odml_document )
128+ msg = ""
129+ for e in validation .errors :
130+ if e .is_error :
131+ msg += "\n \t - %s %s: %s" % (e .obj , e .type , e .msg )
132+ if msg != "" :
133+ msg = "Resolve document validation errors before saving %s" % msg
134+ raise ParserException (msg )
135+
125136 file = open (filename , 'w' )
126137 file .write (self .to_string (odml_document ))
127138 file .close ()
@@ -135,7 +146,7 @@ def to_string(self, odml_document):
135146 self .to_dict (odml_document )
136147 odml_output = {}
137148 odml_output ['Document' ] = self .parsed_doc
138- odml_output ['odml-version' ] = odml_version
149+ odml_output ['odml-version' ] = FORMAT_VERSION
139150
140151 if self .parser == 'YAML' :
141152 string_doc = yaml .dump (odml_output , default_flow_style = False )
@@ -150,8 +161,8 @@ class ODMLReader:
150161 based on the given data exchange format, like XML, YAML or JSON.
151162
152163 Usage:
153- yaml_odml_doc = ODMLReader(parser='YAML').fromFile(open( "odml_doc.yaml") )
154- json_odml_doc = ODMLReader(parser='JSON').fromFile(open( "odml_doc.json") )
164+ yaml_odml_doc = ODMLReader(parser='YAML').from_file( "odml_doc.yaml")
165+ json_odml_doc = ODMLReader(parser='JSON').from_file( "odml_doc.json")
155166 """
156167
157168 def __init__ (self , parser = 'XML' ):
@@ -162,18 +173,29 @@ def __init__(self, parser='XML'):
162173 if parser not in allowed_parsers :
163174 raise NotImplementedError ("'%s' odML parser does not exist!" % parser )
164175 self .parser = parser
176+ self .warnings = []
165177
166178 def is_valid_attribute (self , attr , fmt ):
167179 if attr in fmt ._args :
168180 return attr
169181 if fmt .revmap (attr ):
170182 return attr
171- print ("Invalid element <%s> inside <%s> tag" % (attr , fmt .__class__ .__name__ ))
183+ msg = "Invalid element <%s> inside <%s> tag" % (attr , fmt .__class__ .__name__ )
184+ print (msg )
185+ self .warnings .append (msg )
172186 return None
173187
174188 def to_odml (self ):
175-
176- self .odml_version = self .parsed_doc .get ('odml-version' , odml_version )
189+ # Parse only odML documents of supported format versions.
190+ if 'odml-version' not in self .parsed_doc :
191+ raise ParserException ("Invalid odML document: Could not find odml-version." )
192+ elif self .parsed_doc .get ('odml-version' ) != FORMAT_VERSION :
193+ msg = ("Cannot read file: invalid odML document format version '%s'. \n "
194+ "This package supports odML format versions: '%s'."
195+ % (self .parsed_doc .get ('odml-version' ), FORMAT_VERSION ))
196+ raise ParserException (msg )
197+
198+ self .odml_version = self .parsed_doc .get ('odml-version' )
177199 self .parsed_doc = self .parsed_doc ['Document' ]
178200
179201 doc_attrs = {}
@@ -193,7 +215,6 @@ def to_odml(self):
193215 return self .doc
194216
195217 def parse_sections (self , section_list ):
196-
197218 odml_sections = []
198219
199220 for section in section_list :
@@ -218,7 +239,6 @@ def parse_sections(self, section_list):
218239
219240 return odml_sections
220241
221-
222242 def parse_properties (self , props_list ):
223243 odml_props = []
224244
@@ -257,52 +277,54 @@ def parse_values(self, value_list):
257277
258278 return odml_values
259279
260-
261280 def from_file (self , file ):
262281
263282 if self .parser == 'XML' or self .parser == 'ODML' :
264- odml_doc = xmlparser .XMLReader ().fromFile (file )
283+ par = xmlparser .XMLReader (ignore_errors = True )
284+ self .warnings = par .warnings
285+ odml_doc = par .fromFile (file )
265286 self .doc = odml_doc
266287 return odml_doc
267288
268289 elif self .parser == 'YAML' :
269- try :
270- self . parsed_doc = yaml . load ( file )
271- except yaml . parser . ParserError as e :
272- print ( e )
273- return
274- finally :
275- file . close ()
290+ with open ( file ) as yaml_data :
291+ try :
292+ self . parsed_doc = yaml . load ( yaml_data )
293+ except yaml . parser . ParserError as e :
294+ print ( e )
295+ return
296+
276297 return self .to_odml ()
277298
278299 elif self .parser == 'JSON' :
279- try :
280- self .parsed_doc = json .load (file )
281- except json .decoder .JSONDecodeError as e :
282- print (e )
283- return
284- finally :
285- file .close ()
286- return self .to_odml ()
300+ with open (file ) as json_data :
301+ try :
302+ self .parsed_doc = json .load (json_data )
303+ except ValueError as e : # Python 2 does not support JSONDecodeError
304+ print ("JSON Decoder Error: %s" % e )
305+ return
287306
307+ return self .to_odml ()
288308
289309 def from_string (self , string ):
290310
291311 if self .parser == 'XML' or self .parser == 'ODML' :
292312 odml_doc = xmlparser .XMLReader ().fromString (string )
293313 self .doc = odml_doc
294314 return self .doc
315+
295316 elif self .parser == 'YAML' :
296317 try :
297- odml_doc = yaml .load (string )
318+ self . parsed_doc = yaml .load (string )
298319 except yaml .parser .ParserError as e :
299320 print (e )
300321 return
301322 return self .to_odml ()
323+
302324 elif self .parser == 'JSON' :
303325 try :
304- odml_doc = json .loads (string )
305- except json . decoder . JSONDecodeError as e :
306- print (e )
326+ self . parsed_doc = json .loads (string )
327+ except ValueError as e : # Python 2 does not support JSONDecodeError
328+ print ("JSON Decoder Error: %s" % e )
307329 return
308330 return self .to_odml ()
0 commit comments