[accerciser] Better fix for #709122 - Using an accessor for plugins to handle possible exceptions on them



commit c6a9a8f0c293faa33808a80fbb2c4fbc12555fc5
Author: Javier Hernández <jhernandez emergya com>
Date:   Tue Aug 25 18:08:51 2015 +0200

    Better fix for #709122 - Using an accessor for plugins to handle possible exceptions on them

 src/lib/accerciser/accessible_treeview.py   |    6 ++--
 src/lib/accerciser/node.py                  |    4 +-
 src/lib/accerciser/plugin/base_plugin.py    |   29 ++++---------------------
 src/lib/accerciser/plugin/plugin_manager.py |    4 +-
 src/lib/accerciser/plugin/view.py           |    4 +-
 src/lib/accerciser/tools.py                 |   30 +++++++++++++++++++++++++++
 6 files changed, 44 insertions(+), 33 deletions(-)
---
diff --git a/src/lib/accerciser/accessible_treeview.py b/src/lib/accerciser/accessible_treeview.py
index 7e3309a..4607c7d 100644
--- a/src/lib/accerciser/accessible_treeview.py
+++ b/src/lib/accerciser/accessible_treeview.py
@@ -24,7 +24,7 @@ from . import ui_manager
 from time import sleep
 from .icons import getIcon
 from .node import Node
-from .tools import Tools, getTreePathBoundingBox
+from .tools import ToolsAccessor, getTreePathBoundingBox
 from .i18n import _
 
 COL_ICON = 0
@@ -37,7 +37,7 @@ COL_ACC = 6
 
 ACCESSIBLE_LOADING = 5
 
-class AccessibleModel(gtk.TreeStore, Tools):
+class AccessibleModel(gtk.TreeStore, ToolsAccessor):
   '''
   Stores the desktop accessible tree. Only populates sections of the tree
   that are being viewed. This cuts short on a lot of potential overhead.
@@ -463,7 +463,7 @@ class AccessibleModel(gtk.TreeStore, Tools):
       count = None
     return [icon, name, role, count, False, dummy, accessible]
 
-class AccessibleTreeView(gtk.TreeView, Tools):
+class AccessibleTreeView(gtk.TreeView, ToolsAccessor):
   '''
   The treeview for the desktop's accessibles. The treeview's model (L{AccessibleModel}
   is only populated when the treeview is traversed and nodes are expanded. This class
diff --git a/src/lib/accerciser/node.py b/src/lib/accerciser/node.py
index 9605eb7..4d2d512 100644
--- a/src/lib/accerciser/node.py
+++ b/src/lib/accerciser/node.py
@@ -22,7 +22,7 @@ from gi.repository.Gio import Settings as GSettings
 import cairo
 import pyatspi
 import string
-from .tools import Tools, parseColorString
+from .tools import ToolsAccessor, parseColorString
 
 MAX_BLINKS = 6
 
@@ -45,7 +45,7 @@ class Bag(object):
   def __str__(self):
     return ', '.join(list(vars(self).keys()))
 
-class Node(GObject.GObject, Tools):
+class Node(GObject.GObject, ToolsAccessor):
   '''
   Node class that contains convient references to accessibility information 
   for the currently selected node. A L{Node} instance will emit an 
diff --git a/src/lib/accerciser/plugin/base_plugin.py b/src/lib/accerciser/plugin/base_plugin.py
index 50cf1fc..681aa64 100644
--- a/src/lib/accerciser/plugin/base_plugin.py
+++ b/src/lib/accerciser/plugin/base_plugin.py
@@ -14,10 +14,10 @@ is available at U{http://www.opensource.org/licenses/bsd-license.php}
 import gi
 
 from gi.repository import Gtk as gtk
-from accerciser.tools import Tools
+from accerciser.tools import ToolsAccessor
 import traceback
 
-class Plugin(Tools):
+class Plugin(ToolsAccessor):
   '''
   Base class for all plugins. It contains abstract methods for initializing 
   and finalizing a plugin. It also holds a reference to the main L{Node} and
@@ -100,33 +100,14 @@ class Plugin(Tools):
 
   def onAccChanged(self, acc):
     '''
-    An abstract event handler method that is called when the selected 
-    accessible in the main app changes. Should be overridden by 
+    An abstract event handler method that is called when the selected
+    accessible in the main app changes. Should be overridden by
     L{Plugin} authors.
 
     @param acc: The new accessibility object.
     @type acc: Accessibility.Accessible
     '''
-    pass 
-
-  def __getattribute__(self, name):
-    '''
-    Wraps attributes that are callable in a wrapper. This allows us to 
-    catch exceptions and display them in the plugin view if necessary.
-    
-    @param name: Name of attribure we are seeking.
-    @type name: string
-    
-    @return: Wrap attribut in L{_PluginMethodWrapper} if callable
-    @rtype: object
-    '''
-    obj = super(Plugin, self).__getattribute__(name)
-    if callable(obj) and name not in ['__class__']:
-      method_wrapper = \
-          super(Plugin, self).__getattribute__('_PluginMethodWrapper')
-      return method_wrapper(obj)
-    else:
-      return obj
+    pass
 
   class _PluginMethodWrapper(object):
     '''
diff --git a/src/lib/accerciser/plugin/plugin_manager.py b/src/lib/accerciser/plugin/plugin_manager.py
index 33c304a..cff6c43 100644
--- a/src/lib/accerciser/plugin/plugin_manager.py
+++ b/src/lib/accerciser/plugin/plugin_manager.py
@@ -19,7 +19,7 @@ from gi.repository.Gio import Settings as GSettings
 
 from .base_plugin import Plugin
 from .view import ViewManager
-from accerciser.tools import Tools, getTreePathBoundingBox
+from accerciser.tools import ToolsAccessor, getTreePathBoundingBox
 from .message import MessageManager
 import os
 import sys
@@ -29,7 +29,7 @@ from accerciser.i18n import _, N_, C_
 
 GSCHEMA = 'org.a11y.Accerciser'
 
-class PluginManager(gtk.ListStore, Tools):
+class PluginManager(gtk.ListStore, ToolsAccessor):
   '''
 
   @cvar COL_INSTANCE: Instance column ID.
diff --git a/src/lib/accerciser/plugin/view.py b/src/lib/accerciser/plugin/view.py
index bee97ee..8b486b1 100644
--- a/src/lib/accerciser/plugin/view.py
+++ b/src/lib/accerciser/plugin/view.py
@@ -270,7 +270,7 @@ class PluginView(gtk.Notebook):
     shown_children = [x for x in self.get_children() if x.get_property('visible')]
     return len(shown_children)
 
-class PluginViewWindow(gtk.Window, Tools):
+class PluginViewWindow(gtk.Window, ToolsAccessor):
   '''
   Standalone window with a plugin view.
 
@@ -495,7 +495,7 @@ class ViewManager(object):
     '''
     return self._view_model.Menu(context_plugin, transient_window)
 
-class BaseViewModel(Tools):
+class BaseViewModel(ToolsAccessor):
   '''
   Base class for views model
 
diff --git a/src/lib/accerciser/tools.py b/src/lib/accerciser/tools.py
index 2cb6b6f..059e292 100644
--- a/src/lib/accerciser/tools.py
+++ b/src/lib/accerciser/tools.py
@@ -14,6 +14,9 @@ import os
 import pickle
 import weakref
 
+import traceback
+import functools
+
 class Tools(object):
   '''
   A class with some common methods that more than a few classes will need.
@@ -146,3 +149,30 @@ def getTreePathBoundingBox(treeview, path, col):
   rect.x += x
   rect.y += y
   return rect
+
+def logException(func):
+  '''
+  Handle (and log) the exceptions that are coming from plugins
+  '''
+  @functools.wraps(func)
+  def newfunc(*args, **kwargs):
+    # use Exception otherwise KeyboardInterrupt won't get through
+    try:
+      return func(*args, **kwargs)
+    except Exception:
+      traceback.print_exc()
+  return newfunc
+
+class ToolsAccessor(Tools):
+  '''
+  By following the recommendation on
+  https://bugzilla.gnome.org/show_bug.cgi?id=723081#c4, this Accessor allows us
+  to wrap every plugin's method and in order to catch all possible exceptions
+  and print them appropiately.
+  '''
+  def __init__(self, plugin):
+    self.plugin = plugin
+
+    @logException
+    def method(self):
+      return self.plugin.method()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]