From c806bc75910c129c6d78115cfdc571316e060412 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 12 Dec 2018 18:07:05 +0100
Subject: Reorganized the global variables access in the Python bindings.

---
 plugins/pychrysalide/analysis/project.c |  45 ++++++++++
 plugins/pychrysalide/analysis/project.h |   3 +
 plugins/pychrysalide/core/global.c      | 140 ++++++++++----------------------
 plugins/pychrysalide/core/global.h      |   7 +-
 plugins/pychrysalide/core/module.c      |   2 +-
 plugins/pychrysalide/core/queue.c       |   2 +-
 src/core/global.c                       |   5 +-
 tests/core/global.py                    |  22 +++++
 8 files changed, 119 insertions(+), 107 deletions(-)
 create mode 100644 tests/core/global.py

diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c
index 06a67b6..1a85f71 100644
--- a/plugins/pychrysalide/analysis/project.c
+++ b/plugins/pychrysalide/analysis/project.c
@@ -335,3 +335,48 @@ bool ensure_python_study_project_is_registered(void)
     return true;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
+*                                                                             *
+*  Description : Tente de convertir en projet d'étude.                        *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_study_project(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_study_project_type());
+
+    switch (result)
+    {
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
+
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to study project");
+            break;
+
+        case 1:
+            *((GStudyProject **)dst) = G_STUDY_PROJECT(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/analysis/project.h b/plugins/pychrysalide/analysis/project.h
index 1e0c698..357d958 100644
--- a/plugins/pychrysalide/analysis/project.h
+++ b/plugins/pychrysalide/analysis/project.h
@@ -37,6 +37,9 @@ PyTypeObject *get_python_study_project_type(void);
 /* Prend en charge l'objet 'pychrysalide.analysis.StudyProject'. */
 bool ensure_python_study_project_is_registered(void);
 
+/* Tente de convertir en projet d'étude. */
+int convert_to_study_project(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_PROJECT_H */
diff --git a/plugins/pychrysalide/core/global.c b/plugins/pychrysalide/core/global.c
index e84af68..0a56825 100644
--- a/plugins/pychrysalide/core/global.c
+++ b/plugins/pychrysalide/core/global.c
@@ -38,23 +38,23 @@
 
 
 /* Fournit l'adresse de l'explorateur de contenus courant. */
-static PyObject *py_global_get_content_explorer(PyObject *, void *);
+static PyObject *py_global_get_content_explorer(PyObject *, PyObject *);
 
 /* Fournit l'adresse du résolveur de contenus courant. */
-static PyObject *py_global_get_content_resolver(PyObject *, void *);
+static PyObject *py_global_get_content_resolver(PyObject *, PyObject *);
 
 /* Fournit l'adresse du projet courant. */
-static PyObject *py_global_get_current_project(PyObject *, void *);
+static PyObject *py_global_get_current_project(PyObject *, PyObject *);
 
 /* Définit l'adresse du projet courant. */
-static int py_global_set_current_project(PyObject *, PyObject *, void *);
+static PyObject *py_global_set_current_project(PyObject *, PyObject *);
 
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                closure = non utilisé ici.                                   *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = non utilisé ici.                                      *
 *                                                                             *
 *  Description : Fournit l'adresse de l'explorateur de contenus courant.      *
 *                                                                             *
@@ -64,7 +64,7 @@ static int py_global_set_current_project(PyObject *, PyObject *, void *);
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_global_get_content_explorer(PyObject *self, void *closure)
+static PyObject *py_global_get_content_explorer(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance Python à retourner */
     GContentExplorer *explorer;             /* Gestionnaire natif récupéré */
@@ -89,8 +89,8 @@ static PyObject *py_global_get_content_explorer(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                closure = non utilisé ici.                                   *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = non utilisé ici.                                      *
 *                                                                             *
 *  Description : Fournit l'adresse du résolveur de contenus courant.          *
 *                                                                             *
@@ -100,7 +100,7 @@ static PyObject *py_global_get_content_explorer(PyObject *self, void *closure)
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_global_get_content_resolver(PyObject *self, void *closure)
+static PyObject *py_global_get_content_resolver(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance Python à retourner */
     GContentResolver *resolver;             /* Gestionnaire natif récupéré */
@@ -125,8 +125,8 @@ static PyObject *py_global_get_content_resolver(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                closure = non utilisé ici.                                   *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = non utilisé ici.                                      *
 *                                                                             *
 *  Description : Fournit l'adresse du projet courant.                         *
 *                                                                             *
@@ -136,7 +136,7 @@ static PyObject *py_global_get_content_resolver(PyObject *self, void *closure)
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_global_get_current_project(PyObject *self, void *closure)
+static PyObject *py_global_get_current_project(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance Python à retourner */
     GStudyProject *project;                 /* Projet courant récupéré     */
@@ -154,8 +154,6 @@ static PyObject *py_global_get_current_project(PyObject *self, void *closure)
         Py_INCREF(result);
     }
 
-    printf("result: %p (project=%p)\n", result, project);
-
     return result;
 
 }
@@ -163,9 +161,8 @@ static PyObject *py_global_get_current_project(PyObject *self, void *closure)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self    = objet Python concerné par l'appel.                 *
-*                value   = valeur fournie à intégrer ou prendre en compte.    *
-*                closure = adresse non utilisée ici.                          *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = valeur fournie à intégrer ou prendre en compte.       *
 *                                                                             *
 *  Description : Définit l'adresse du projet courant.                         *
 *                                                                             *
@@ -175,21 +172,19 @@ static PyObject *py_global_get_current_project(PyObject *self, void *closure)
 *                                                                             *
 ******************************************************************************/
 
-static int py_global_set_current_project(PyObject *self, PyObject *value, void *closure)
+static PyObject *py_global_set_current_project(PyObject *self, PyObject *args)
 {
-    int ret;                                /* Bilan d'analyse             */
-    GStudyProject *project;                 /* Version GLib du format      */
-
-    ret = PyObject_IsInstance(value, (PyObject *)get_python_study_project_type());
-    if (!ret) return -1;
+    GStudyProject *project;                 /* Version GLib du projet      */
+    int ret;                                /* Bilan de lecture des args.  */
 
-    project = G_STUDY_PROJECT(pygobject_get(value));
+    ret = PyArg_ParseTuple(args, "O&", convert_to_study_project, &project);
+    if (!ret) return NULL;
 
     g_object_ref(G_OBJECT(project));
 
     set_current_project(project);
 
-    return 0;
+    Py_RETURN_NONE;
 
 }
 
@@ -198,94 +193,45 @@ static int py_global_set_current_project(PyObject *self, PyObject *value, void *
 *                                                                             *
 *  Paramètres  : -                                                            *
 *                                                                             *
-*  Description : Fournit un accès à une définition de type à diffuser.        *
+*  Description : Définit une extension du module 'core' à compléter.          *
 *                                                                             *
-*  Retour      : Définition d'objet pour Python.                              *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-PyTypeObject *get_python_global_type(void)
+bool populate_core_module_with_global(void)
 {
+    bool result;                            /* Bilan à retourner           */
+    PyObject *module;                       /* Module à recompléter        */
+
     static PyMethodDef py_global_methods[] = {
-        { NULL }
-    };
 
-    static PyGetSetDef py_global_getseters[] = {
-        {
-            "content_explorer", py_global_get_content_explorer, NULL,
-            "Get the global exploration manager discovering contents.", NULL
+        { "get_content_explorer", py_global_get_content_explorer,
+          METH_NOARGS,
+          "get_content_explorer(, /)\n--\n\nGet the global exploration manager discovering contents."
+        },
+        { "get_content_resolver", py_global_get_content_resolver,
+          METH_NOARGS,
+          "get_content_resolver(, /)\n--\n\nGet the global resolution manager translating binary contents into loaded contents."
         },
-        {
-            "content_resolver", py_global_get_content_resolver, NULL,
-            "Get the global resolution manager translating binary contents into loaded contents.", NULL
+        { "get_current_project", py_global_get_current_project,
+          METH_NOARGS,
+          "get_current_project(, /)\n--\n\nGet the current global project."
         },
-        {
-            "current_project", py_global_get_current_project, py_global_set_current_project,
-            "Get or set the current global project.", NULL
+        { "set_current_project", py_global_set_current_project,
+          METH_VARARGS,
+          "set_current_project(, /)\n--\n\nSet the current global project."
         },
         { NULL }
-    };
-
-    static PyTypeObject py_global_type = {
-
-        PyVarObject_HEAD_INIT(NULL, 0)
-
-        .tp_name = "pychrysalide.core._global",
-        .tp_basicsize = sizeof(PyObject),
-
-        .tp_flags = Py_TPFLAGS_DEFAULT,
-
-        .tp_doc = "Access to the global properties",
-
-        .tp_methods = py_global_methods,
-        .tp_getset  = py_global_getseters
 
     };
 
-    return &py_global_type;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : module = module dont la définition est à compléter.          *
-*                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide.core._global'.         *
-*                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-bool ensure_python_global_is_registered(void)
-{
-    PyTypeObject *type;                     /* Type Python de 'global'     */
-    PyObject *module;                       /* Module à recompléter        */
-    int ret;                                /* Bilan d'un appel            */
-
-    type = get_python_global_type();
-
-    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
-    {
-        type->tp_new = PyType_GenericNew;
-
-        if (PyType_Ready(type) != 0)
-            return false;
+    module = get_access_to_python_module("pychrysalide.core");
 
-        module = get_access_to_python_module("pychrysalide.core");
+    result = register_python_module_methods(module, py_global_methods);
 
-        Py_INCREF(type);
-        ret = PyModule_AddObject(module, "_global", (PyObject *)type);
-
-        if (ret != 0)
-            return false;
-
-    }
-
-    return true;
+    return result;
 
 }
diff --git a/plugins/pychrysalide/core/global.h b/plugins/pychrysalide/core/global.h
index 3246947..07fb0ad 100644
--- a/plugins/pychrysalide/core/global.h
+++ b/plugins/pychrysalide/core/global.h
@@ -31,11 +31,8 @@
 
 
 
-/* Fournit un accès à une définition de type à diffuser. */
-PyTypeObject *get_python_global_type(void);
-
-/* Prend en charge l'objet 'pychrysalide.core._global'. */
-bool ensure_python_global_is_registered(void);
+/* Définit une extension du module 'core' à compléter. */
+bool populate_core_module_with_global(void);
 
 
 
diff --git a/plugins/pychrysalide/core/module.c b/plugins/pychrysalide/core/module.c
index aade384..900bf83 100644
--- a/plugins/pychrysalide/core/module.c
+++ b/plugins/pychrysalide/core/module.c
@@ -93,7 +93,7 @@ bool populate_core_module(void)
     result = true;
 
     if (result) result = ensure_python_demanglers_is_registered();
-    if (result) result = ensure_python_global_is_registered();
+    if (result) result = populate_core_module_with_global();
     if (result) result = ensure_python_logs_is_registered();
     if (result) result = ensure_python_params_is_registered();
     if (result) result = populate_core_module_with_queue();
diff --git a/plugins/pychrysalide/core/queue.c b/plugins/pychrysalide/core/queue.c
index 8d530e6..39dd576 100644
--- a/plugins/pychrysalide/core/queue.c
+++ b/plugins/pychrysalide/core/queue.c
@@ -43,7 +43,7 @@ static PyObject *py_queue_wait_for_all_global_works(PyObject *, PyObject *);
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = NULL car méthode statique.                            *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
 *                args = non utilisé ici.                                      *
 *                                                                             *
 *  Description : Attend que toutes les tâches de tout groupe soient traitées. *
diff --git a/src/core/global.c b/src/core/global.c
index 8736b30..3777fd9 100644
--- a/src/core/global.c
+++ b/src/core/global.c
@@ -261,9 +261,8 @@ void set_current_project(GStudyProject *project)
 
 GStudyProject *get_current_project(void)
 {
-    assert(_project != NULL);
-
-    g_object_ref(G_OBJECT(_project));
+    if (_project != NULL)
+        g_object_ref(G_OBJECT(_project));
 
     return _project;
 
diff --git a/tests/core/global.py b/tests/core/global.py
new file mode 100644
index 0000000..a929940
--- /dev/null
+++ b/tests/core/global.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python3-dbg
+# -*- coding: utf-8 -*-
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis import StudyProject
+from pychrysalide.core import get_current_project, set_current_project
+
+
+class TestCoreGlobal(ChrysalideTestCase):
+    """TestCase for analysis.core.global."""
+
+    def testProject(self):
+        """Get and set the current project."""
+
+        self.assertIsNone(get_current_project())
+
+        prj = StudyProject()
+
+        set_current_project(prj)
+
+        self.assertEqual(get_current_project(), prj)
-- 
cgit v0.11.2-87-g4458