From fcc78751e1e733b8662fde7d5e8ac6023cb34582 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sat, 12 Aug 2017 17:08:53 +0200 Subject: Fixed many mistakes in the Python bindings. --- ChangeLog | 11 +++ plugins/pychrysa/glibext/configuration.c | 3 - plugins/pychrysa/gtkext/blockdisplay.c | 19 ++-- plugins/pychrysa/gtkext/bufferdisplay.c | 19 ++-- plugins/pychrysa/gtkext/displaypanel.c | 14 +-- plugins/pychrysa/helpers.c | 152 ++++++++++++++++++++++++++++++- plugins/pychrysa/helpers.h | 10 ++ plugins/pychrysa/pychrysa.c | 35 ++----- 8 files changed, 200 insertions(+), 63 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4981236..9cc2a11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +17-08-12 Cyrille Bagard + + * plugins/pychrysa/glibext/configuration.c: + * plugins/pychrysa/gtkext/blockdisplay.c: + * plugins/pychrysa/gtkext/bufferdisplay.c: + * plugins/pychrysa/gtkext/displaypanel.c: + * plugins/pychrysa/helpers.c: + * plugins/pychrysa/helpers.h: + * plugins/pychrysa/pychrysa.c: + Fix many mistakes in the Python bindings. + 17-08-07 Cyrille Bagard * plugins/pychrysa/arch/processor.c: diff --git a/plugins/pychrysa/glibext/configuration.c b/plugins/pychrysa/glibext/configuration.c index 58eafb3..3ced957 100644 --- a/plugins/pychrysa/glibext/configuration.c +++ b/plugins/pychrysa/glibext/configuration.c @@ -1155,9 +1155,6 @@ bool register_python_generic_config(PyObject *module) py_generic_config_type = get_python_generic_config_type(); - if (PyType_Ready(py_generic_config_type) != 0) - return false; - dict = PyModule_GetDict(module); if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, py_generic_config_type, &PyGObject_Type)) diff --git a/plugins/pychrysa/gtkext/blockdisplay.c b/plugins/pychrysa/gtkext/blockdisplay.c index a329daf..c2ccfbb 100644 --- a/plugins/pychrysa/gtkext/blockdisplay.c +++ b/plugins/pychrysa/gtkext/blockdisplay.c @@ -66,7 +66,7 @@ PyTypeObject *get_python_block_display_type(void) .tp_name = "pychrysalide.gtkext.BlockDisplay", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "PyChrysalide block display.", @@ -78,12 +78,7 @@ PyTypeObject *get_python_block_display_type(void) static PyTypeObject *result = NULL; if (result == NULL) - { - result = calloc(1, sizeof(PyTypeObject)); - - memcpy(result, &py_block_display_type, sizeof(PyTypeObject)); - - } + result = define_python_dynamic_type(&py_block_display_type); return result; @@ -104,17 +99,17 @@ PyTypeObject *get_python_block_display_type(void) bool register_python_block_display(PyObject *module) { - PyTypeObject *py_block_display_type; /* Type Python 'BlockDisplay' */ + bool result; /* Bilan à retourner */ + PyTypeObject *py_block_display_type; /* Type Python 'BlockDisplay' */ PyObject *dict; /* Dictionnaire du module */ py_block_display_type = get_python_block_display_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, - py_block_display_type, get_python_buffer_display_type())) - return false; + result = register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, + py_block_display_type, get_python_buffer_display_type()); - return true; + return result; } diff --git a/plugins/pychrysa/gtkext/bufferdisplay.c b/plugins/pychrysa/gtkext/bufferdisplay.c index a6e5327..9aa1bca 100644 --- a/plugins/pychrysa/gtkext/bufferdisplay.c +++ b/plugins/pychrysa/gtkext/bufferdisplay.c @@ -66,7 +66,7 @@ PyTypeObject *get_python_buffer_display_type(void) .tp_name = "pychrysalide.gtkext.BufferDisplay", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "PyChrysalide buffer display.", @@ -78,12 +78,7 @@ PyTypeObject *get_python_buffer_display_type(void) static PyTypeObject *result = NULL; if (result == NULL) - { - result = calloc(1, sizeof(PyTypeObject)); - - memcpy(result, &py_buffer_display_type, sizeof(PyTypeObject)); - - } + result = define_python_dynamic_type(&py_buffer_display_type); return result; @@ -104,17 +99,17 @@ PyTypeObject *get_python_buffer_display_type(void) bool register_python_buffer_display(PyObject *module) { - PyTypeObject *py_buffer_display_type; /* Type Python 'Bufferdisplay' */ + bool result; /* Bilan à retourner */ + PyTypeObject *py_buffer_display_type; /* Type Python 'BufferDisplay' */ PyObject *dict; /* Dictionnaire du module */ py_buffer_display_type = get_python_buffer_display_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, - py_buffer_display_type, get_python_display_panel_type())) - return false; + result = register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, + py_buffer_display_type, get_python_display_panel_type()); - return true; + return result; } diff --git a/plugins/pychrysa/gtkext/displaypanel.c b/plugins/pychrysa/gtkext/displaypanel.c index e857475..aa166e5 100644 --- a/plugins/pychrysa/gtkext/displaypanel.c +++ b/plugins/pychrysa/gtkext/displaypanel.c @@ -197,7 +197,7 @@ PyTypeObject *get_python_display_panel_type(void) .tp_name = "pychrysalide.gtkext.DisplayPanel", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "PyChrysalide view panel.", @@ -211,12 +211,7 @@ PyTypeObject *get_python_display_panel_type(void) static PyTypeObject *result = NULL; if (result == NULL) - { - result = calloc(1, sizeof(PyTypeObject)); - - memcpy(result, &py_display_panel_type, sizeof(PyTypeObject)); - - } + result = define_python_dynamic_type(&py_display_panel_type); return result; @@ -248,7 +243,9 @@ bool register_python_display_panel(PyObject *module) py_display_panel_type = get_python_display_panel_type(); parent_mod = PyImport_ImportModule("gi.repository.Gtk"); - if (parent_mod == NULL) return false; + + if (parent_mod == NULL) + goto rpdp_exit; fixed = PyObject_GetAttrString(parent_mod, "Fixed"); @@ -258,7 +255,6 @@ bool register_python_display_panel(PyObject *module) result = register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, py_display_panel_type, (PyTypeObject *)fixed); - Py_DECREF(fixed); if (!result) diff --git a/plugins/pychrysa/helpers.c b/plugins/pychrysa/helpers.c index a0a828f..17a396d 100644 --- a/plugins/pychrysa/helpers.c +++ b/plugins/pychrysa/helpers.c @@ -27,9 +27,15 @@ #include #include #include +#include +/* ---------------------------------------------------------------------------------- */ +/* ACCELERATEURS POUR PYTHON UNIQUEMENT */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : status = bilan de comparaison à traduire. * @@ -242,6 +248,126 @@ bool PyDict_AddStringConstant(PyTypeObject *obj_type, const char *key, const cha } + +/* ---------------------------------------------------------------------------------- */ +/* CONFORTS CIBLANT PYGOBJECT */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : spec = définition à mettre en place dynamiquement. * +* * +* Description : Définit dans le tas de Python un nouveau type. * +* * +* Retour : Nouveau type prêt à emploi. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *define_python_dynamic_type(const PyTypeObject *spec) +{ + PyTypeObject *result; /* Définition créée à renvoyer */ + PyTypeObject *type; /* Type de tous les types */ + size_t size; /* Taille de la définition */ + char *s; /* Marqueur de début de chaîne */ + PyHeapTypeObject *hobj; /* Version réelle du type créé */ + + /** + * Le cahier des charges est ici d'éviter les erreurs suivantes : + * + * TypeError: type 'XXX' is not dynamically allocated but its base type 'YYY' is dynamically allocated + * Fatal Python error: unexpected exception during garbage collection + * + * L'allocation dynamique est marquée par le fanion Py_TPFLAGS_HEAPTYPE. + * + * Une des rares fonctions qui appliquent ce fanion est PyType_FromSpecWithBases(), + * mais elle appelle ensuite PyType_Ready(), ce qui est incompatible avec des modifications + * utltérieures avant un appel à pygobject_register_class(). + * + * Le code suivant s'inspire fortement des méthodes originales de Python, + * dont les mécanismes employés par PyType_GenericAlloc(). + */ + + type = &PyType_Type; + size = _PyObject_SIZE(type); + + if (PyType_IS_GC(type)) + result = (PyTypeObject *)_PyObject_GC_Malloc(size); + else + result = (PyTypeObject *)PyObject_MALLOC(size); + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_INCREF(type); + + /* Définitions sommaires */ + + memset(result, 0, sizeof(PyHeapTypeObject)); + + memcpy(result, spec, sizeof(PyTypeObject)); + + result->tp_flags |= Py_TPFLAGS_HEAPTYPE; + + /* Définitions des noms */ + + /** + * Pour un type dynamique, les désignations ne s'appuient pas sur la partie réservée + * au type, mais sur les données suivantes (cf. type_name() et type_qualname()). + * + * Les deux fonctions désignées sont par ailleurs facilement accessibles : + * + * #0 0x0000555555689bf0 in type_qualname (...) at Objects/typeobject.c:393 + * #1 0x000055555568b3b4 in type_repr (...) at Objects/typeobject.c:855 + * #2 0x0000555555693574 in object_str (...) at Objects/typeobject.c:3511 + * #3 0x0000555555670d02 in PyObject_Str (...) at Objects/object.c:535 + * ... + * + * On s'inspire donc du contenu de PyType_FromSpecWithBases() pour éviter tout + * plantage du fait de données non initialisées. + */ + + hobj = (PyHeapTypeObject *)result; + + s = strrchr(spec->tp_name, '.'); + + if (s == NULL) + s = (char *)spec->tp_name; + else + s++; + + hobj->ht_name = PyUnicode_FromString(s); + assert(hobj->ht_name != NULL); + + hobj->ht_qualname = hobj->ht_name; + Py_INCREF(hobj->ht_qualname); + + result->tp_as_async = &hobj->as_async; + result->tp_as_number = &hobj->as_number; + result->tp_as_sequence = &hobj->as_sequence; + result->tp_as_mapping = &hobj->as_mapping; + result->tp_as_buffer = &hobj->as_buffer; + + hobj->ht_cached_keys = _PyDict_NewKeysForClass(); + + + + +#if 0 + if (type->tp_itemsize == 0) + (void)PyObject_INIT(result, type); + else + (void) PyObject_INIT_VAR((PyVarObject *)result, type, 0); + + if (PyType_IS_GC(type)) + _PyObject_GC_TRACK(result); +#endif + + return result; + +} + + /****************************************************************************** * * * Paramètres : module = module où conserver une référence au type créé. * @@ -259,6 +385,7 @@ bool PyDict_AddStringConstant(PyTypeObject *obj_type, const char *key, const cha bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type, PyTypeObject *base, ...) { + bool result; /* Bilan à retourner */ Py_ssize_t size; /* Taille de liste actuelle */ PyObject *static_bases; /* Base(s) de l'objet */ va_list ap; /* Parcours des arguments */ @@ -314,10 +441,33 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty va_end(ap); + + + /* +#0 0x000055555565aad4 in insertdict (mp=0x7fffe7c2c8a8, key='GenConfig', hash=262970853803706525, value=) at ../Objects/dictobject.c:801 +#1 0x000055555565bf62 in PyDict_SetItem (op={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': , '__spec__': None, 'ConfigParam': , '__package__': None, 'Buffercache': , 'ConfigParamIterator': , '__loader__': None}, key='GenConfig', value=) at ../Objects/dictobject.c:1227 +#2 0x00005555556610b0 in PyDict_SetItemString (v={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': , '__spec__': None, 'ConfigParam': , '__package__': None, 'Buffercache': , 'ConfigParamIterator': , '__loader__': None}, key=0x7ffff69cd0bd "GenConfig", item=) at ../Objects/dictobject.c:2870 +#3 0x00007ffff69b3d12 in _register_class_for_pygobject (dict={'__doc__': 'Python module for Chrysalide.glibext', '__name__': 'pychrysalide.glibext', 'BufferLine': , '__spec__': None, 'ConfigParam': , '__package__': None, 'Buffercache': , 'ConfigParamIterator': , '__loader__': None}, gtype=93824998785328, type=0x7ffff6bd9ce0 , base=0x7fffe80e72a0 ) at helpers.c:320 + */ + + + + //type->tp_weaklistoffset = offsetof(PyGObject, weakreflist); + //type->tp_dictoffset = offsetof(PyGObject, inst_dict); + pygobject_register_class(dict, NULL, gtype, type, static_bases); + if (PyErr_Occurred() == NULL) + result = true; + + else + { + PyErr_Print(); + result = false; + } + assert(PyErr_Occurred() == NULL); - return true; + return result; } diff --git a/plugins/pychrysa/helpers.h b/plugins/pychrysa/helpers.h index 9fb83d0..3eee6a0 100644 --- a/plugins/pychrysa/helpers.h +++ b/plugins/pychrysa/helpers.h @@ -31,6 +31,9 @@ +/* ---------------------- ACCELERATEURS POUR PYTHON UNIQUEMENT ---------------------- */ + + /* Traduit pour Python le bilan d'une comparaison riche. */ PyObject *status_to_rich_cmp_state(int, int); @@ -54,6 +57,10 @@ bool PyDict_AddStringConstant(PyTypeObject *, const char *, const char *); #define PyDict_AddStringMacro(tp, c) PyDict_AddStringConstant(tp, #c, c) + +/* --------------------------- CONFORTS CIBLANT PYGOBJECT --------------------------- */ + + /** * Quelque chose est mal fait au niveau de l'abstraction GObject. * Du coup, Py_TPFLAGS_IS_ABSTRACT n'est pas pris en compte. @@ -64,6 +71,9 @@ bool PyDict_AddStringConstant(PyTypeObject *, const char *, const char *); #define APPLY_ABSTRACT_FLAG(tp) tp->tp_new = PyBaseObject_Type.tp_new +/* Définit dans le tas de Python un nouveau type. */ +PyTypeObject *define_python_dynamic_type(const PyTypeObject *); + /* Enregistre correctement une surcouche de conversion GObject. */ bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObject *, ...); diff --git a/plugins/pychrysa/pychrysa.c b/plugins/pychrysa/pychrysa.c index f959671..bcd2284 100644 --- a/plugins/pychrysa/pychrysa.c +++ b/plugins/pychrysa/pychrysa.c @@ -332,7 +332,6 @@ static bool set_version_for_gtk_namespace(const char *version) PyMODINIT_FUNC PyInit_pychrysalide(void) { PyObject *result; /* Module Python à retourner */ - PyObject *pygobj_mod; /* Module Python-GObject */ bool status; /* Bilan des inclusions */ static PyMethodDef py_chrysalide_methods[] = { @@ -370,8 +369,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) }; - - #if 0 do { @@ -425,20 +422,6 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) return NULL; } - /* Préparatifs préalables aux chargements */ - - /** - * Pour une raison non identifiée, si le module n'est pas préchargé, - * le flot d'exécution plante dans la fonction insertdict() de Objects/dictobject.c:818. - */ - - pygobj_mod = PyImport_ImportModule("gi.repository.GObject"); - if (pygobj_mod == NULL) - { - PyErr_SetString(PyExc_ImportError, "could not import gi.gobject"); - return NULL; - } - /* Mise en place des fonctionnalités offertes */ result = PyModule_Create(&py_chrysalide_module); @@ -446,15 +429,15 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) /* Interface 'LineGenerator' en premier... */ status = add_glibext_module_to_python_module(result); - status &= register_python_plugin_module(result); - status &= add_analysis_module_to_python_module(result); - status &= add_arch_module_to_python_module(result); - status &= add_common_module_to_python_module(result); - status &= add_core_module_to_python_module(result); - status &= add_debug_module_to_python_module(result); - status &= add_format_module_to_python_module(result); - status &= add_gtkext_module_to_python_module(result); - status &= add_gui_module_to_python_module(result); + if (status) status = register_python_plugin_module(result); + if (status) status = add_analysis_module_to_python_module(result); + if (status) status = add_arch_module_to_python_module(result); + if (status) status = add_common_module_to_python_module(result); + if (status) status = add_core_module_to_python_module(result); + if (status) status = add_debug_module_to_python_module(result); + if (status) status = add_format_module_to_python_module(result); + if (status) status = add_gtkext_module_to_python_module(result); + if (status) status = add_gui_module_to_python_module(result); if (!status) { -- cgit v0.11.2-87-g4458