diff options
author | Garrett Regier <garrettregier@gmail.com> | 2015-01-20 01:13:05 -0800 |
---|---|---|
committer | Garrett Regier <garrettregier@gmail.com> | 2015-01-20 01:23:07 -0800 |
commit | e42c5820852c009582e2c58a0fbcb45daaa8660c (patch) | |
tree | 1b6dc16e1d98a625883d8d351e740ce886271f4e /loaders | |
parent | 83a44f3c0e610814923a29c419b4a1ba16fbee08 (diff) | |
download | libpeas-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.c | 29 | ||||
-rw-r--r-- | 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] |