[libpeas] Add verbose Python plugin loader warnings



commit e42c5820852c009582e2c58a0fbcb45daaa8660c
Author: Garrett Regier <garrettregier gmail com>
Date:   Tue Jan 20 01:13:05 2015 -0800

    Add verbose Python plugin loader warnings
    
    Use a Python hook to implement the call logic.
    This allows us to have verbose error messages
    and include the exception traceback.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=742349

 loaders/python/peas-python-internal.c  |   29 ++++++++++++-----------------
 loaders/python/peas-python-internal.py |   19 +++++++++++++++++++
 2 files changed, 31 insertions(+), 17 deletions(-)
---
diff --git a/loaders/python/peas-python-internal.c b/loaders/python/peas-python-internal.c
index 8175898..227c1b5 100644
--- a/loaders/python/peas-python-internal.c
+++ b/loaders/python/peas-python-internal.c
@@ -37,15 +37,21 @@ static PyObject *
 failed_fn (PyObject *self,
            PyObject *args)
 {
-  const char *msg;
+  const gchar *msg;
+  gchar *clean_msg;
 
   if (!PyArg_ParseTuple (args, "s:Hooks.failed", &msg))
     return NULL;
 
-  g_warning ("%s", msg);
+  /* Python tracebacks have a trailing newline */
+  clean_msg = g_strchomp (g_strdup (msg));
+
+  g_warning ("%s", clean_msg);
 
   /* peas_python_internal_call() knows to check for this exception */
   PyErr_SetObject (FailedError, NULL);
+
+  g_free (clean_msg);
   return NULL;
 }
 
@@ -183,7 +189,7 @@ peas_python_internal_call (PeasPythonInternal *internal,
                            ...)
 {
   PyObject *internal_ = (PyObject *) internal;
-  PyObject *callable, *args;
+  PyObject *args;
   PyObject *result = NULL;
   va_list var_args;
 
@@ -191,16 +197,14 @@ peas_python_internal_call (PeasPythonInternal *internal,
   if (return_type == NULL)
     return_type = Py_None->ob_type;
 
-  callable = PyObject_GetAttrString (internal_, name);
-  g_return_val_if_fail (callable != NULL, NULL);
-
   va_start (var_args, format);
   args = Py_VaBuildValue (format == NULL ? "()" : format, var_args);
   va_end (var_args);
 
   if (args != NULL)
     {
-      result = PyObject_CallObject (callable, args);
+      result = PyObject_CallMethod (internal_, "call", "(sOO)",
+                                    name, args, return_type);
       Py_DECREF (args);
     }
 
@@ -220,17 +224,8 @@ peas_python_internal_call (PeasPythonInternal *internal,
       return NULL;
     }
 
-  /* We always allow a None result */
   if (result == Py_None)
-    {
-      Py_CLEAR (result);
-    }
-  else if (!PyObject_TypeCheck (result, return_type))
-    {
-      g_warning ("Failed to run internal Python hook '%s': ", name);
-
-      Py_CLEAR (result);
-    }
+    Py_CLEAR (result);
 
   return result;
 }
diff --git a/loaders/python/peas-python-internal.py b/loaders/python/peas-python-internal.py
index 991d2f9..dcffaeb 100644
--- a/loaders/python/peas-python-internal.py
+++ b/loaders/python/peas-python-internal.py
@@ -58,6 +58,25 @@ class Hooks(object):
         # This is implemented by the plugin loader
         raise NotImplementedError('Hooks.failed()')
 
+    def call(self, name, args, return_type):
+        try:
+            result = getattr(self, name)(*args)
+
+        except FailedError:
+            raise
+
+        except:
+            self.failed("Failed to run internal Python hook '%s':\n%s" %
+                        (name, traceback.format_exc()))
+
+        # We always allow None
+        if result is not None and not isinstance(result, return_type):
+            self.failed("Failed to run internal Python hook '%s': "
+                        "expected %s, got %s" %
+                        (name, return_type, result))
+
+        return result
+
     def load(self, filename, module_dir, module_name):
         try:
             return self.__module_cache[filename]


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