Changeset 11303:9401b375eba0 in orange


Ignore:
Timestamp:
02/04/13 18:14:00 (15 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Error handling/recovery in scheme parsing code.

Location:
Orange/OrangeCanvas
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeCanvas/application/canvasmain.py

    r11299 r11303  
    3131from ..gui.dock import CollapsibleDockWidget 
    3232from ..gui.quickhelp import QuickHelpTipEvent 
    33 from ..gui.utils import message_critical, message_question 
     33from ..gui.utils import message_critical, message_question, message_warning 
    3434 
    3535from ..help import HelpManager 
     
    4343 
    4444from ..scheme import widgetsscheme 
     45from ..scheme.readwrite import parse_scheme 
    4546 
    4647from . import welcomedialog 
     
    867868        """ 
    868869        new_scheme = widgetsscheme.WidgetsScheme() 
     870        errors = [] 
    869871        try: 
    870             new_scheme.load_from(open(filename, "rb")) 
     872            parse_scheme(new_scheme, open(filename, "rb"), 
     873                         error_handler=errors.append) 
    871874        except Exception: 
    872875            message_critical( 
    873876                 self.tr("Could not load Orange Scheme file"), 
    874877                 title=self.tr("Error"), 
    875                  informative_text=self.tr("An unexpected error occurred"), 
     878                 informative_text=self.tr("An unexpected error occurred " 
     879                                          "while loading %r.") % filename, 
    876880                 exc_info=True, 
    877881                 parent=self) 
    878882            return None 
    879  
     883        if errors: 
     884            message_warning( 
     885                self.tr("Errors occured while loading the scheme."), 
     886                title=self.tr("Problem"), 
     887                informative_text=self.tr( 
     888                     "There were problems loading some " 
     889                     "of the widgets/links in the " 
     890                     "scheme." 
     891                ), 
     892                details="\n".join(map(repr, errors)) 
     893            ) 
    880894        return new_scheme 
    881895 
  • Orange/OrangeCanvas/preview/scanner.py

    r11213 r11303  
    44""" 
    55import sys 
    6  
    76import logging 
    87 
    98from xml.sax import make_parser, handler, saxutils, SAXParseException 
    109 
     10from ..scheme.readwrite import parse_scheme 
    1111log = logging.getLogger(__name__) 
    1212 
     
    7878 
    7979    scheme = scheme.Scheme() 
    80     scheme.load_from(scheme_file) 
     80    errors = [] 
     81    parse_scheme(scheme, scheme_file, error_handler=errors.append) 
     82 
    8183    tmp_scene = scene.CanvasScene() 
    8284    tmp_scene.set_registry(global_registry()) 
  • Orange/OrangeCanvas/scheme/readwrite.py

    r11210 r11303  
    66import shutil 
    77 
    8 from xml.etree.ElementTree import TreeBuilder, Element, ElementTree 
     8from xml.etree.ElementTree import TreeBuilder, Element, ElementTree, parse 
    99from xml.dom import minidom 
    1010 
     
    1717import logging 
    1818 
    19 from . import SchemeNode 
    20 from . import SchemeLink 
     19from . import SchemeNode, SchemeLink 
    2120from .annotations import SchemeTextAnnotation, SchemeArrowAnnotation 
     21from .errors import IncompatibleChannelTypeError 
    2222 
    2323from .. import registry 
     
    2626 
    2727 
    28 def parse_scheme(scheme, stream): 
    29     """Parse a saved scheme from `stream` and populate a `scheme` 
     28class UnknownWidgetDefinition(Exception): 
     29    pass 
     30 
     31 
     32def parse_scheme(scheme, stream, error_handler=None): 
     33    """ 
     34    Parse a saved scheme from `stream` and populate a `scheme` 
    3035    instance (:class:`Scheme`). 
    31  
    32     """ 
    33     from xml.etree.ElementTree import parse 
     36    `error_handler` if given will be called with an exception when 
     37    a 'recoverable' error occurs. By default the exception is simply 
     38    raised. 
     39 
     40    """ 
    3441    doc = parse(stream) 
    3542    scheme_el = doc.getroot() 
     
    4249            version = "2.0" 
    4350 
     51    if error_handler is None: 
     52        def error_handler(exc): 
     53            raise exc 
     54 
    4455    if version == "1.0": 
    45         parse_scheme_v_1_0(doc, scheme) 
     56        parse_scheme_v_1_0(doc, scheme, error_handler=error_handler) 
    4657        return scheme 
    4758    else: 
    48         parse_scheme_v_2_0(doc, scheme) 
     59        parse_scheme_v_2_0(doc, scheme, error_handler=error_handler) 
    4960        return scheme 
    5061 
    5162 
    5263def scheme_node_from_element(node_el, registry): 
    53     """Create a SchemeNode from an Element instance. 
    54     """ 
    55     widget_desc = registry.widget(node_el.get("qualified_name")) 
     64    """ 
     65    Create a SchemeNode from an `Element` instance. 
     66    """ 
     67    try: 
     68        widget_desc = registry.widget(node_el.get("qualified_name")) 
     69    except KeyError as ex: 
     70        raise UnknownWidgetDefinition(*ex.args) 
     71 
    5672    title = node_el.get("title") 
    5773    pos = node_el.get("position") 
     
    6379 
    6480 
    65 def parse_scheme_v_2_0(etree, scheme, widget_registry=None): 
    66     """Parse an ElementTree Instance. 
     81def parse_scheme_v_2_0(etree, scheme, error_handler, widget_registry=None): 
     82    """ 
     83    Parse an `ElementTree` instance. 
    6784    """ 
    6885    if widget_registry is None: 
    6986        widget_registry = registry.global_registry() 
     87 
     88    nodes_not_found = [] 
    7089 
    7190    nodes = [] 
     
    8099    # Load and create scheme nodes. 
    81100    for node_el in etree.findall("nodes/node"): 
    82         # TODO: handle errors. 
    83101        try: 
    84102            node = scheme_node_from_element(node_el, widget_registry) 
     103        except UnknownWidgetDefinition, ex: 
     104            # description was not found 
     105            error_handler(ex) 
     106            node = None 
    85107        except Exception: 
    86108            raise 
    87109 
    88         nodes.append(node) 
    89         id_to_node[node_el.get("id")] = node 
     110        if node is not None: 
     111            nodes.append(node) 
     112            id_to_node[node_el.get("id")] = node 
     113        else: 
     114            nodes_not_found.append(node_el.get("id")) 
    90115 
    91116    # Load and create scheme links. 
    92117    for link_el in etree.findall("links/link"): 
    93         source = id_to_node[link_el.get("source_node_id")] 
    94         sink = id_to_node[link_el.get("sink_node_id")] 
     118        source_id = link_el.get("source_node_id") 
     119        sink_id = link_el.get("sink_node_id") 
     120 
     121        if source_id in nodes_not_found or sink_id in nodes_not_found: 
     122            continue 
     123 
     124        source = id_to_node.get(source_id) 
     125        sink = id_to_node.get(sink_id) 
     126 
    95127        source_channel = link_el.get("source_channel") 
    96128        sink_channel = link_el.get("sink_channel") 
    97129        enabled = link_el.get("enabled") == "true" 
    98         link = SchemeLink(source, source_channel, sink, sink_channel, 
    99                           enabled=enabled) 
    100         links.append(link) 
     130 
     131        try: 
     132            link = SchemeLink(source, source_channel, sink, sink_channel, 
     133                              enabled=enabled) 
     134        except (ValueError, IncompatibleChannelTypeError) as ex: 
     135            error_handler(ex) 
     136        else: 
     137            links.append(link) 
    101138 
    102139    # Load node properties 
    103140    for property_el in etree.findall("node_properties/properties"): 
    104141        node_id = property_el.attrib.get("node_id") 
     142 
     143        if node_id in nodes_not_found: 
     144            continue 
     145 
    105146        node = id_to_node[node_id] 
    106147 
     
    160201 
    161202 
    162 def parse_scheme_v_1_0(etree, scheme, widget_registry=None): 
    163     """ElementTree Instance of an old .ows scheme format. 
     203def parse_scheme_v_1_0(etree, scheme, error_handler, widget_registry=None): 
     204    """ 
     205    ElementTree Instance of an old .ows scheme format. 
    164206    """ 
    165207    if widget_registry is None: 
    166208        widget_registry = registry.global_registry() 
     209 
     210    widgets_not_found = [] 
    167211 
    168212    widgets = widget_registry.widgets() 
     
    179223        x_pos = widget_el.get("xPos") 
    180224        y_pos = widget_el.get("yPos") 
    181         desc = widgets_by_name[name] 
     225 
     226        if name in widgets_by_name: 
     227            desc = widgets_by_name[name] 
     228        else: 
     229            error_handler(UnknownWidgetDefinition(name)) 
     230            widgets_not_found.append(caption) 
     231            continue 
     232 
    182233        node = SchemeNode(desc, title=caption, 
    183234                          position=(int(x_pos), int(y_pos))) 
    184235        nodes_by_caption[caption] = node 
    185236        nodes.append(node) 
    186 #        scheme.add_node(node) 
    187237 
    188238    for channel_el in etree.findall("channels/channel"): 
    189239        in_caption = channel_el.get("inWidgetCaption") 
    190240        out_caption = channel_el.get("outWidgetCaption") 
     241 
     242        if in_caption in widgets_not_found or \ 
     243                out_caption in widgets_not_found: 
     244            continue 
     245 
    191246        source = nodes_by_caption[out_caption] 
    192247        sink = nodes_by_caption[in_caption] 
    193248        enabled = channel_el.get("enabled") == "1" 
    194         signals = eval(channel_el.get("signals")) 
     249        signals = literal_eval(channel_el.get("signals")) 
     250 
    195251        for source_channel, sink_channel in signals: 
    196             link = SchemeLink(source, source_channel, sink, sink_channel, 
    197                               enabled=enabled) 
    198             links.append(link) 
    199 #            scheme.add_link(link) 
     252            try: 
     253                link = SchemeLink(source, source_channel, sink, sink_channel, 
     254                                  enabled=enabled) 
     255            except (ValueError, IncompatibleChannelTypeError) as ex: 
     256                error_handler(ex) 
     257            else: 
     258                links.append(link) 
    200259 
    201260    settings = etree.find("settings") 
Note: See TracChangeset for help on using the changeset viewer.