summaryrefslogtreecommitdiff
path: root/loaders
diff options
context:
space:
mode:
authorGarrett Regier <garrettregier@gmail.com>2015-01-20 01:13:05 -0800
committerGarrett Regier <garrettregier@gmail.com>2015-01-20 01:23:07 -0800
commite42c5820852c009582e2c58a0fbcb45daaa8660c (patch)
tree1b6dc16e1d98a625883d8d351e740ce886271f4e /loaders
parent83a44f3c0e610814923a29c419b4a1ba16fbee08 (diff)
downloadlibpeas-e42c5820852c009582e2c58a0fbcb45daaa8660c.tar.gz
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
Diffstat (limited to 'loaders')
-rw-r--r--loaders/python/peas-python-internal.c29
-rw-r--r--loaders/python/peas-python-internal.py19
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]