[gobject-introspection] giscanner: Port scanner extension module to work with Python 3



commit ae198873254769bd49207003d25b47d12b096e2f
Author: Simon Feltman <sfeltman src gnome org>
Date:   Mon Apr 28 20:25:30 2014 -0700

    giscanner: Port scanner extension module to work with Python 3
    
    Define portable macros for use between Python 2 and 3.
    Replace usage of PyString related functions with PyBytes.
    Update pygi_source_scanner_parse_macros to support both
    PyBytes and PyUnicode.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=679438

 Makefile-giscanner.am       |    3 +-
 giscanner/giscannermodule.c |  104 +++++++++++++++++++++++++++++++------------
 2 files changed, 77 insertions(+), 30 deletions(-)
---
diff --git a/Makefile-giscanner.am b/Makefile-giscanner.am
index 5bc8425..b0e1373 100644
--- a/Makefile-giscanner.am
+++ b/Makefile-giscanner.am
@@ -114,7 +114,8 @@ _giscanner_la_CFLAGS = \
 _giscanner_la_LIBADD = libgiscanner.la $(GOBJECT_LIBS)
 
 _giscanner_la_LDFLAGS = \
-       -module -avoid-version -export-symbols-regex init_giscanner
+       -module -avoid-version \
+       -export-symbols-regex "init_giscanner|PyInit__giscanner"
 
 if OS_WIN32
 # Windows requires Python extension modules to be explicitly
diff --git a/giscanner/giscannermodule.c b/giscanner/giscannermodule.c
index f6945da..845a72f 100644
--- a/giscanner/giscannermodule.c
+++ b/giscanner/giscannermodule.c
@@ -39,32 +39,38 @@
 
 #include <glib-object.h>
 
-DL_EXPORT(void) init_giscanner(void);
+#ifndef Py_TYPE
+    #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+    #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
+    #define MOD_ERROR_RETURN NULL
+    #define PyInt_FromLong PyLong_FromLong
+#else
+    #define MOD_INIT(name) DL_EXPORT(void) init##name(void)
+    #define MOD_ERROR_RETURN
+#endif
+
+/* forward declaration */
+MOD_INIT(_giscanner);
 
 #define NEW_CLASS(ctype, name, cname, num_methods)           \
 static const PyMethodDef _Py##cname##_methods[num_methods];    \
 PyTypeObject Py##cname##_Type = {             \
-    PyObject_HEAD_INIT(NULL)                  \
-    0,                                       \
+    PyVarObject_HEAD_INIT(NULL, 0)            \
     "scanner." name,                          \
-    sizeof(ctype),                           \
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0,            \
-    0, 0, 0, 0,        0, 0,                         \
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, \
-    NULL, 0, 0, 0,                           \
-    0,       \
-    0, 0,                                     \
-    0,                                        \
-    0, 0, NULL, NULL, 0, 0,                  \
-    0             \
+    sizeof(ctype),                            \
+    0                                         \
 }
 
 #define REGISTER_TYPE(d, name, type)         \
-    type.ob_type = &PyType_Type;              \
+    Py_TYPE(&type) = &PyType_Type;             \
     type.tp_alloc = PyType_GenericAlloc;      \
     type.tp_new = PyType_GenericNew;          \
+    type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; \
     if (PyType_Ready (&type))                 \
-       return;                               \
+        return MOD_ERROR_RETURN;              \
     PyDict_SetItemString (d, name, (PyObject *)&type); \
     Py_INCREF (&type);
 
@@ -402,16 +408,34 @@ pygi_source_scanner_parse_macros (PyGISourceScanner *self,
   for (i = 0; i < PyList_Size (list); ++i)
     {
       PyObject *obj;
-      char *filename;
+      char *filename = NULL;
 
       obj = PyList_GetItem (list, i);
-      filename = PyString_AsString (obj);
+      if (PyUnicode_Check (obj))
+        {
+          PyObject *s = PyUnicode_AsUTF8String (obj);
+          filename = g_strdup (PyBytes_AsString (s));
+          Py_DECREF (s);
+        }
+      else if (PyBytes_Check (obj))
+        {
+          filename = g_strdup (PyBytes_AsString (obj));
+        }
+
+      if (filename == NULL)
+        {
+          PyErr_Format (PyExc_RuntimeError,
+                        "Expected string but got %s",
+                        (Py_TYPE(obj))->tp_name);
+          g_list_free_full (filenames, g_free);
+          return NULL;
+        }
 
       filenames = g_list_append (filenames, filename);
     }
 
   gi_source_scanner_parse_macros (self->scanner, filenames);
-  g_list_free (filenames);
+  g_list_free_full (filenames, g_free);
 
   Py_INCREF (Py_None);
   return Py_None;
@@ -669,9 +693,9 @@ static int calc_attrs_length(PyObject *attributes, int indent,
         if (!s) {
           return -1;
         }
-        value = PyString_AsString(s);
-      } else if (PyString_Check(pyvalue)) {
-        value = PyString_AsString(pyvalue);
+        value = PyBytes_AsString(s);
+      } else if (PyBytes_Check(pyvalue)) {
+        value = PyBytes_AsString(pyvalue);
       } else {
         PyErr_SetString(PyExc_TypeError,
                         "value must be string or unicode");
@@ -756,9 +780,9 @@ pygi_collect_attributes (PyObject *self,
         s = PyUnicode_AsUTF8String(pyvalue);
         if (!s)
          goto out;
-        value = PyString_AsString(s);
-      } else if (PyString_Check(pyvalue)) {
-        value = PyString_AsString(pyvalue);
+        value = PyBytes_AsString(s);
+      } else if (PyBytes_Check(pyvalue)) {
+        value = PyBytes_AsString(pyvalue);
       } else {
         PyErr_SetString(PyExc_TypeError,
                         "value must be string or unicode");
@@ -792,25 +816,43 @@ pygi_collect_attributes (PyObject *self,
 
 /* Module */
 
-static const PyMethodDef pyscanner_functions[] = {
+static PyMethodDef pyscanner_functions[] = {
   { "collect_attributes",
     (PyCFunction) pygi_collect_attributes, METH_VARARGS },
   { NULL, NULL, 0, NULL }
 };
 
-DL_EXPORT(void)
-init_giscanner(void)
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+       PyModuleDef_HEAD_INIT,
+       NULL, /* m_name */
+       NULL, /* m_doc */
+       0,
+       pyscanner_functions,
+       NULL
+};
+#endif /* PY_MAJOR_VERSION >= 3 */
+
+
+MOD_INIT(_giscanner)
 {
     PyObject *m, *d;
     gboolean is_uninstalled;
+    const char *module_name;
 
     /* Hack to avoid having to create a fake directory structure; when
      * running uninstalled, the module will be in the top builddir,
      * with no _giscanner prefix.
      */
     is_uninstalled = g_getenv ("UNINSTALLED_INTROSPECTION_SRCDIR") != NULL;
-    m = Py_InitModule (is_uninstalled ? "_giscanner" : "giscanner._giscanner",
-                      (PyMethodDef*)pyscanner_functions);
+    module_name = is_uninstalled ? "_giscanner" : "giscanner._giscanner";
+
+#if PY_MAJOR_VERSION >= 3
+    moduledef.m_name = module_name;
+    m = PyModule_Create (&moduledef);
+#else
+    m = Py_InitModule (module_name, (PyMethodDef*)pyscanner_functions);
+#endif
     d = PyModule_GetDict (m);
 
     PyGISourceScanner_Type.tp_init = (initproc)pygi_source_scanner_init;
@@ -822,4 +864,8 @@ init_giscanner(void)
 
     PyGISourceType_Type.tp_getset = (PyGetSetDef*)_PyGISourceType_getsets;
     REGISTER_TYPE (d, "SourceType", PyGISourceType_Type);
+
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]