diff options
-rw-r--r-- | grc/base/ParseXML.py | 33 | ||||
-rw-r--r-- | grc/base/Platform.py | 10 | ||||
-rw-r--r-- | grc/gui/ActionHandler.py | 9 | ||||
-rw-r--r-- | grc/gui/ParseDialog.py | 108 |
4 files changed, 88 insertions, 72 deletions
diff --git a/grc/base/ParseXML.py b/grc/base/ParseXML.py index d66edffb69..abb6576ac2 100644 --- a/grc/base/ParseXML.py +++ b/grc/base/ParseXML.py @@ -20,14 +20,18 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from lxml import etree from . import odict -xml_failures = {}; +xml_failures = {} + class XMLSyntaxError(Exception): def __init__(self, error_log): self._error_log = error_log + xml_failures[error_log.last_error.filename] = error_log + def __str__(self): return '\n'.join(map(str, self._error_log.filter_from_errors())) + def validate_dtd(xml_file, dtd_file=None): """ Validate an xml file against its dtd. @@ -38,16 +42,22 @@ def validate_dtd(xml_file, dtd_file=None): @throws Exception validation fails """ #perform parsing, use dtd validation if dtd file is not specified - parser = etree.XMLParser(dtd_validation=not dtd_file) - xml = etree.parse(xml_file, parser=parser) - if parser.error_log: - xml_failures[xml_file] = parser.error_log; + try: + parser = etree.XMLParser(dtd_validation=not dtd_file) + xml = etree.parse(xml_file, parser=parser) + except etree.LxmlError: + pass + if parser.error_log: raise XMLSyntaxError(parser.error_log) - #perform dtd validation if the dtd file is specified - if not dtd_file: return - dtd = etree.DTD(dtd_file) - if not dtd.validate(xml.getroot()): - xml_failures[xml_file] = dtd.error_log; + + # perform dtd validation if the dtd file is specified + if not dtd_file: + return + try: + dtd = etree.DTD(dtd_file) + if not dtd.validate(xml.getroot()): + raise XMLSyntaxError(dtd.error_log) + except etree.LxmlError: raise XMLSyntaxError(dtd.error_log) def from_file(xml_file): @@ -63,6 +73,7 @@ def from_file(xml_file): xml = etree.parse(xml_file).getroot() return _from_file(xml) + def _from_file(xml): """ Recursivly parse the xml tree into nested data format. @@ -87,6 +98,7 @@ def _from_file(xml): return odict({tag: nested_data}) + def to_file(nested_data, xml_file): """ Write an xml file and use the to xml helper method to load it. @@ -98,6 +110,7 @@ def to_file(nested_data, xml_file): xml = _to_file(nested_data)[0] open(xml_file, 'w').write(etree.tostring(xml, xml_declaration=True, pretty_print=True)) + def _to_file(nested_data): """ Recursivly parse the nested data into xml tree format. diff --git a/grc/base/Platform.py b/grc/base/Platform.py index 66266b1b71..e1b3839483 100644 --- a/grc/base/Platform.py +++ b/grc/base/Platform.py @@ -81,7 +81,7 @@ class Platform(_Element): self._blocks_n = odict() self._block_tree_files = list() for xml_file in xml_files: - try: #try to add the xml file as a block wrapper + try: # try to add the xml file as a block wrapper ParseXML.validate_dtd(xml_file, self._block_dtd) n = ParseXML.from_file(xml_file).find('block') #inject block wrapper path @@ -96,13 +96,15 @@ class Platform(_Element): self._blocks[key] = block self._blocks_n[key] = n except ParseXML.XMLSyntaxError, e: - try: #try to add the xml file as a block tree + try: # try to add the xml file as a block tree ParseXML.validate_dtd(xml_file, BLOCK_TREE_DTD) self._block_tree_files.append(xml_file) - # remove the block DTD error, since iti s a valid block tree - ParseXML.xml_failures.pop(xml_file) + # remove the block DTD error, since it is a valid block tree except ParseXML.XMLSyntaxError, e: print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file) + else: + del ParseXML.xml_failures[xml_file] + except Exception, e: print >> sys.stderr, 'Warning: Block loading failed:\n\t%s\n\tIgnoring: %s'%(e, xml_file) diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index e5c382793f..2a564c3e16 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -115,8 +115,10 @@ class ActionHandler: Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY, Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW, - Actions.TOGGLE_REPORTS_WINDOW, Actions.PARSER_ERRORS, + Actions.TOGGLE_REPORTS_WINDOW, ): action.set_sensitive(True) + Actions.PARSER_ERRORS.set_sensitive(bool(ParseXML.xml_failures)) + if not self.init_file_paths: self.init_file_paths = Preferences.files_open() if not self.init_file_paths: self.init_file_paths = [''] @@ -461,8 +463,9 @@ class ActionHandler: pass elif action == Actions.RELOAD_BLOCKS: self.platform.loadblocks() - self.main_window.btwin.clear(); - self.platform.load_block_tree(self.main_window.btwin); + self.main_window.btwin.clear() + self.platform.load_block_tree(self.main_window.btwin) + Actions.PARSER_ERRORS.set_sensitive(bool(ParseXML.xml_failures)) elif action == Actions.FIND_BLOCKS: self.main_window.btwin.show() self.main_window.btwin.search_entry.show() diff --git a/grc/gui/ParseDialog.py b/grc/gui/ParseDialog.py index 93fa108e81..119ad2c69b 100644 --- a/grc/gui/ParseDialog.py +++ b/grc/gui/ParseDialog.py @@ -19,77 +19,75 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import pygtk pygtk.require('2.0') -import gtk, glib +import gtk -from Dialogs import TextDisplay from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT -def get_title_label(title): - """ - Get a title label for the params window. - The title will be bold, underlined, and left justified. - - Args: - title: the text of the title - - Returns: - a gtk object - """ - label = gtk.Label() - label.set_markup('\n<b><span underline="low">%s</span>:</b>\n'%title) - hbox = gtk.HBox() - hbox.pack_start(label, False, False, padding=11) - return hbox class ParseDialog(gtk.Dialog): """ A dialog for viewing parser errors """ - def __init__(self, errors): + def __init__(self, error_logs): """ - Properties dialog contructor. + Properties dialog constructor. Args: block: a block instance """ - self._hash = 0 - LABEL_SPACING = 7 - gtk.Dialog.__init__(self, - title='Parser Errors', - buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT), - ) - - self._errors = errors; - - # set up data model - model = gtk.TreeStore(str) - for k in self._errors.keys(): - n = model.append(None, [str(k)]); - for e in self._errors[k]: - # http://lxml.de/api/lxml.etree._LogEntry-class.html - em = model.append(n, [ "(%s:%s:%s) %s %s %s"%(e.filename, e.line, e.column, e.level_name, e.domain_name, e.message) ] ) - try: - sf = open(e.filename,'r'); - lc = sf.readlines()[e.line].rstrip('\n'); - model.append(em, [ lc] ) - except: - model.append(em, ["could not access source file"] ) - - - view = gtk.TreeView(model) - tvcolumn = gtk.TreeViewColumn('XML Parser Errors by Filename') - view.append_column(tvcolumn) - cell = gtk.CellRendererText() - tvcolumn.pack_start(cell, True) - tvcolumn.add_attribute(cell, 'text', 0) - view.set_search_column(0) - tvcolumn.set_sort_column_id(0) - view.set_reorderable(True) - - self.vbox.add(view); + gtk.Dialog.__init__(self, title='Parser Errors', buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT)) + + self._error_logs = None + self.tree_store = gtk.TreeStore(str) + self.update_tree_store(error_logs) + + column = gtk.TreeViewColumn('XML Parser Errors by Filename') + renderer = gtk.CellRendererText() + column.pack_start(renderer, True) + column.add_attribute(renderer, 'text', 0) + column.set_sort_column_id(0) + + self.tree_view = tree_view = gtk.TreeView(self.tree_store) + tree_view.set_enable_search(False) #disable pop up search box + tree_view.set_search_column(-1) # really disable search + tree_view.set_reorderable(False) + tree_view.set_headers_visible(False) + tree_view.get_selection().set_mode(gtk.SELECTION_NONE) + tree_view.append_column(column) + + for row in self.tree_store: + tree_view.expand_row(row.path, False) + + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window.add_with_viewport(tree_view) + + self.vbox.pack_start(scrolled_window, True) + self.set_size_request(2*MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) self.show_all() + def update_tree_store(self, error_logs): + """set up data model""" + self.tree_store.clear() + self._error_logs = error_logs + for filename, errors in error_logs.iteritems(): + parent = self.tree_store.append(None, [str(filename)]) + try: + with open(filename, 'r') as fp: + code = fp.readlines() + except EnvironmentError: + code = None + for error in errors: + # http://lxml.de/api/lxml.etree._LogEntry-class.html + em = self.tree_store.append(parent, ["Line {e.line}: {e.message}".format(e=error)]) + if code: + self.tree_store.append(em, ["\n".join( + "{} {}{}".format(line, code[line - 1].replace("\t", " ").strip("\n"), + " " * 20 + "<!-- ERROR -->" if line == error.line else "") + for line in range(error.line - 2, error.line + 3) if 0 < line <= len(code) + )]) + def run(self): """ Run the dialog and get its response. |