From 49ae908b6aa3c8c6bca2c79b0a68f587f51b600f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 20 May 2024 00:30:44 +0200
Subject: Load the GLib module from the GI repository at Python bindings
 startup.

---
 plugins/pychrysalide/core.c | 97 ++++++++++++++++++++++++++++++++++++++++++++-
 plugins/pychrysalide/core.h |  3 ++
 2 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index 1157e73..c7ebf72 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -525,7 +525,9 @@ static void PyExit_pychrysalide(void)
     "In both cases, this is a good start point to have a look at already existing plugins to quickly learn "    \
     "how the API works.\n"                                                                                      \
     "\n"                                                                                                        \
-    "These plugins are located in the 'plugins/python' directory."
+    "These plugins are located in the 'plugins/python' directory.\n"                                            \
+    "\n"                                                                                                        \
+    "The *pychrysalide* module imports the GLib module (version 2.0) from the GI repository at startup."
 
 PyMODINIT_FUNC PyInit_pychrysalide(void)
 {
@@ -591,6 +593,30 @@ PyMODINIT_FUNC PyInit_pychrysalide(void)
     if (!install_metaclass_for_python_gobjects())
         goto exit;
 
+    /**
+     * Le chargement forcé de l'espace GLib pour Python permet d'éviter un écueil,
+     * à savoir des types convertis de façon incomplète. Par exemple, pour une
+     * structure GChecksum, le type à l'exécution est :
+     *
+     *    - sans module GLib : [<class 'gobject.GBoxed'>, <class 'object'>]
+     *
+     *    - avec module GLib : [<class 'gi.repository.GLib.Checksum'>, <class 'gi.Boxed'>, <class 'gobject.GBoxed'>, <class 'object'>]
+     *
+     * Par ailleurs, il est à noter que le message suivant n'apparaît qu'avec
+     * la version debug de Python3 (version de python3-gi : 3.42.2-3) :
+     *
+     *    <frozen importlib._bootstrap>:673: ImportWarning: DynamicImporter.exec_module() not found; falling back to load_module()
+     *
+     * Code de reproduction dans un interpréteur classique :
+     *
+     *    import gi
+     *    gi.require_version('GLib', '2.0')
+     *    from gi.repository import GLib
+     *
+     */
+    if (!import_namespace_from_gi_repository("GLib", "2.0"))
+        goto exit;
+
 #if 0
 #ifdef INCLUDE_GTK_SUPPORT
     if (!set_version_for_gtk_namespace("3.0"))
@@ -1174,6 +1200,75 @@ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *pl
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : namespace = module particulier à charger à partir de gi.     *
+*                version   = idenfiant de la version à stipuler.              *
+*                                                                             *
+*  Description : Charge un module GI dans Python avec une version attendue.   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool import_namespace_from_gi_repository(const char *namespace, const char *version)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *module;                       /* Module Python-GObject       */
+    PyObject *args;                         /* Arguments à fournir         */
+    int ret;                                /* Bilan d'une mise en place   */
+
+    result = false;
+
+    /* Sélection d'une version */
+
+    module = PyImport_ImportModule("gi");
+
+    if (module != NULL)
+    {
+        args = Py_BuildValue("ss", namespace, version);
+
+        run_python_method(module, "require_version", args);
+
+        result = (PyErr_Occurred() == NULL);
+
+        Py_DECREF(args);
+        Py_DECREF(module);
+
+    }
+
+    /* Importation du module visé */
+
+    if (result)
+    {
+        args = PyTuple_New(1);
+
+        ret = PyTuple_SetItem(args, 0, PyUnicode_FromString(namespace));
+        if (ret != 0)
+        {
+            result = false;
+            goto args_error;
+        }
+
+        module = PyImport_ImportModuleEx("gi.repository", NULL, NULL, args);
+
+        result = (module != NULL);
+
+        Py_XDECREF(module);
+
+ args_error:
+
+        Py_DECREF(args);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : prefix = message d'introduction à faire apparaître à l'écran.*
 *                                                                             *
 *  Description : Présente dans le journal une exception survenue.             *
diff --git a/plugins/pychrysalide/core.h b/plugins/pychrysalide/core.h
index 88c4140..5d25d3d 100644
--- a/plugins/pychrysalide/core.h
+++ b/plugins/pychrysalide/core.h
@@ -55,6 +55,9 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *, Plugin
 /* Crée une instance à partir d'un type dynamique externe. */
 G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *, PluginAction, GType);
 
+/* Charge un module GI dans Python avec une version attendue. */
+bool import_namespace_from_gi_repository(const char *, const char *);
+
 /* Présente dans le journal une exception survenue. */
 void log_pychrysalide_exception(const char *, ...);
 
-- 
cgit v0.11.2-87-g4458