From ce583a69951bf9a94ca46bcf9f598cdc94b80e29 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 28 Jan 2019 23:41:41 +0100
Subject: Improved handling of NotImplemented exceptions for Python calls.

---
 plugins/pychrysalide/helpers.c | 78 +++++++++++++++++++++++++-----------------
 plugins/pychrysalide/helpers.h |  3 --
 2 files changed, 46 insertions(+), 35 deletions(-)

diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index d4c56e8..a0aa5e7 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -28,6 +28,7 @@
 #include <malloc.h>
 #include <pygobject.h>
 #include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 
 
@@ -48,6 +49,14 @@ static bool include_python_type_into_features(PyObject *, PyTypeObject *);
 
 
 
+/* --------------------------- CONFORTS CIBLANT PYGOBJECT --------------------------- */
+
+
+/* Message d'erreur affiché puis recherché. */
+#define NOT_IMPLEMENTED_MSG _("Chrysalide method implementation is missing")
+
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                        ACCELERATEURS POUR PYTHON UNIQUEMENT                        */
 /* ---------------------------------------------------------------------------------- */
@@ -190,8 +199,9 @@ bool has_python_method(PyObject *module, const char *method)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : func = fonction Python à appeler.                            *
-*                args = arguments à associer à l'opération.                   *
+*  Paramètres  : target = propriétaire de la routine visée.                   *
+*                method = désignation de la fonction à appeler.               *
+*                args   = arguments à associer à l'opération.                 *
 *                                                                             *
 *  Description : Appelle une routine Python.                                  *
 *                                                                             *
@@ -201,51 +211,55 @@ bool has_python_method(PyObject *module, const char *method)
 *                                                                             *
 ******************************************************************************/
 
-PyObject *_run_python_method(PyObject *func, PyObject *args)
+PyObject *run_python_method(PyObject *module, const char *method, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
+    PyObject *func;                         /* Fonction visée              */
+    PyObject *type;                         /* Type d'exception levée      */
+    PyObject *value;                        /* Détails particuliers        */
+    PyObject *traceback;                    /* Pile d'appels de l'exception*/
+    PyObject *refmsg;                       /* Message de référence        */
+
+    /* Exécution */
 
     result = NULL;
 
+    func = PyObject_GetAttrString(module, method);
+    if (func == NULL) goto check_error;
+
     if (PyCallable_Check(func))
-    {
         result = PyObject_CallObject(func, args);
-        if (result == NULL) PyErr_Print();
-    }
-    else if (PyErr_Occurred()) PyErr_Print();
 
-    return result;
+    Py_DECREF(func);
 
-}
+    /* Répercutions */
 
+ check_error:
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : target = propriétaire de la routine visée.                   *
-*                method = désignation de la fonction à appeler.               *
-*                args   = arguments à associer à l'opération.                 *
-*                                                                             *
-*  Description : Appelle une routine Python.                                  *
-*                                                                             *
-*  Retour      : Retour obtenu ou NULL si erreur.                             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+    PyErr_Fetch(&type, &value, &traceback);
 
-PyObject *run_python_method(PyObject *module, const char *method, PyObject *args)
-{
-    PyObject *result;                       /* Bilan à retourner           */
-    PyObject *func;                         /* Fonction visée              */
+    if (type != NULL && type == PyExc_NotImplementedError \
+        && value != NULL && PyUnicode_Check(value) == 1)
+    {
+        refmsg = PyUnicode_FromString(NOT_IMPLEMENTED_MSG);
 
-    result = NULL;
+        if (PyUnicode_Compare(value, refmsg) == 0)
+        {
+            Py_DECREF(value);
+            value = PyUnicode_FromFormat(_("method implementation is missing for '%s'"), method);
+        }
 
-    func = PyObject_GetAttrString(module, method);
-    if (func == NULL) return NULL;
+        Py_DECREF(refmsg);
 
-    result = _run_python_method(func, args);
+    }
 
-    Py_DECREF(func);
+    PyErr_Restore(type, value, traceback);
+
+    if (result == NULL && PyErr_Occurred() != NULL)
+        PyErr_Print();
+
+    if (result == NULL)
+        Py_Exit(EXIT_FAILURE);
 
     return result;
 
@@ -547,7 +561,7 @@ PyObject *not_yet_implemented_method(PyObject *self, PyObject *args)
 
     result = NULL;
 
-    PyErr_SetString(PyExc_NotImplementedError, _("Implementated method is missing"));
+    PyErr_SetString(PyExc_NotImplementedError, NOT_IMPLEMENTED_MSG);
 
     return result;
 
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index ffbfe30..edc6686 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -45,9 +45,6 @@ int convert_to_callable(PyObject *, void *);
 bool has_python_method(PyObject *, const char *);
 
 /* Appelle une routine Python. */
-PyObject *_run_python_method(PyObject *, PyObject *);
-
-/* Appelle une routine Python. */
 PyObject *run_python_method(PyObject *, const char *, PyObject *);
 
 /* Ajoute une constante au dictionnaire d'un type Python donné. */
-- 
cgit v0.11.2-87-g4458