pytalloc: Port to Python 3
authorPetr Viktorin <pviktori@redhat.com>
Thu, 15 Jan 2015 13:07:09 +0000 (14:07 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 19 May 2015 17:28:18 +0000 (19:28 +0200)
- Use native string for repr

- Use rich comparison
  Removes the deprecated tp_compare in favor of tp_richcompare.
  Disparate types cannot be compared (except for == and !=),
  and True or False objects are returned explicitly.

- Use Py_TYPE instead of ob_type
  This changed to conform to C aliasing rules,
  see http://legacy.python.org/dev/peps/pep-3123/

- Don't provide CObject creation function
  A PyCapsule based replacement would be possible,
  but might not be necessary considering the function is
  not used much.

- Use new-style module initialization

Build changes:

- Use ABI flag in the lib name and pkg-config template

- Use the SAMBA_CHECK_PYTHON macro for finding Python

Signed-off-by: Petr Viktorin <pviktori@redhat.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Jelmer Vernooij <jelmer@samba.org>
lib/talloc/pytalloc-util.pc.in
lib/talloc/pytalloc.c
lib/talloc/pytalloc.h
lib/talloc/pytalloc_guide.txt
lib/talloc/pytalloc_util.c
lib/talloc/test_pytalloc.c
lib/talloc/test_pytalloc.py
lib/talloc/wscript

index b7426bb1124d5c03af4b1351e1e1c55d039d6f82..b87c94edf20c5325d3cde598bfa914bd478ed815 100644 (file)
@@ -6,6 +6,6 @@ includedir=@includedir@
 Name: pytalloc-util
 Description: Utility functions for using talloc objects with Python
 Version: @TALLOC_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util
+Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util@PYTHON_SO_ABI_FLAG@
 Cflags: -I${includedir}
 URL: http://talloc.samba.org/
index ac4fe0f41ec81199cb3a57defd38551e26d2e10d..3afae9ce012bffae82e1170544c98e9d5e97f394 100644 (file)
 #include <talloc.h>
 #include <pytalloc.h>
 
-void inittalloc(void);
+static PyTypeObject TallocObject_Type;
+
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_FromFormat PyUnicode_FromFormat
+#else
+#define PyStr_FromFormat PyString_FromFormat
+#endif
 
 /* print a talloc tree report for a talloc python object */
 static PyObject *pytalloc_report_full(PyObject *self, PyObject *args)
@@ -79,8 +85,8 @@ static PyObject *pytalloc_default_repr(PyObject *obj)
        pytalloc_Object *talloc_obj = (pytalloc_Object *)obj;
        PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
 
-       return PyString_FromFormat("<%s talloc object at 0x%p>", 
-                                  type->tp_name, talloc_obj->ptr);
+       return PyStr_FromFormat("<%s talloc object at 0x%p>",
+                               type->tp_name, talloc_obj->ptr);
 }
 
 /**
@@ -97,6 +103,35 @@ static void pytalloc_dealloc(PyObject* self)
 /**
  * Default (but only slightly more useful than the default) implementation of cmp.
  */
+#if PY_MAJOR_VERSION >= 3
+static PyObject *pytalloc_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+       void *ptr1;
+       void *ptr2;
+       if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+               /* When types match, compare pointers */
+               ptr1 = pytalloc_get_ptr(obj1);
+               ptr2 = pytalloc_get_ptr(obj2);
+       } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+               /* Otherwise, compare types */
+               ptr1 = Py_TYPE(obj1);
+               ptr2 = Py_TYPE(obj2);
+       } else {
+               Py_INCREF(Py_NotImplemented);
+               return Py_NotImplemented;
+       }
+       switch (op) {
+               case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+               case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+               case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+               case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+               case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+               case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+       }
+       Py_INCREF(Py_NotImplemented);
+       return Py_NotImplemented;
+}
+#else
 static int pytalloc_default_cmp(PyObject *_obj1, PyObject *_obj2)
 {
        pytalloc_Object *obj1 = (pytalloc_Object *)_obj1,
@@ -106,6 +141,7 @@ static int pytalloc_default_cmp(PyObject *_obj1, PyObject *_obj2)
 
        return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
 }
+#endif
 
 static PyTypeObject TallocObject_Type = {
        .tp_name = "talloc.Object",
@@ -114,21 +150,56 @@ static PyTypeObject TallocObject_Type = {
        .tp_dealloc = (destructor)pytalloc_dealloc,
        .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
        .tp_repr = pytalloc_default_repr,
+#if PY_MAJOR_VERSION >= 3
+       .tp_richcompare = pytalloc_default_richcmp,
+#else
        .tp_compare = pytalloc_default_cmp,
+#endif
 };
 
-void inittalloc(void)
+#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "talloc",
+    .m_doc = MODULE_DOC,
+    .m_size = -1,
+    .m_methods = talloc_methods,
+};
+#endif
+
+static PyObject *module_init(void);
+static PyObject *module_init(void)
 {
        PyObject *m;
 
        if (PyType_Ready(&TallocObject_Type) < 0)
-               return;
+               return NULL;
 
-       m = Py_InitModule3("talloc", talloc_methods,
-                                          "Python wrapping of talloc-maintained objects.");
+#if PY_MAJOR_VERSION >= 3
+       m = PyModule_Create(&moduledef);
+#else
+       m = Py_InitModule3("talloc", talloc_methods, MODULE_DOC);
+#endif
        if (m == NULL)
-               return;
+               return NULL;
 
        Py_INCREF(&TallocObject_Type);
        PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
+       return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit_talloc(void);
+PyMODINIT_FUNC PyInit_talloc(void)
+{
+       return module_init();
+}
+#else
+void inittalloc(void);
+void inittalloc(void)
+{
+       module_init();
 }
+#endif
index 5c3876ed156a58aa23ea15193c234a5edf46277d..608328e6aca36336b38a5ce6b6a742f1a02facfd 100644 (file)
@@ -52,6 +52,8 @@ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void
 
 #define pytalloc_new(type, typeobj) pytalloc_steal(typeobj, talloc_zero(NULL, type))
 
+#if PY_MAJOR_VERSION < 3
 PyObject *pytalloc_CObject_FromTallocPtr(void *);
+#endif
 
 #endif /* _PYTALLOC_H_ */
index 755a52bd21745cd035cb64286b2468f4659e9788..36ae5ffe053bdf83f8f2808bbc1355e139ee55e8 100644 (file)
@@ -20,6 +20,14 @@ for objects that wrap talloc-maintained memory in C. It won't write your
 bindings for you but it will make it easier to write C bindings that involve
 talloc, and take away some of the boiler plate.
 
+Python 3
+--------
+
+pytalloc can be used with Python 3. Usage from Python extension remains
+the same, but for the C utilities, the library to link to is tagged with
+Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
+To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
+.
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 pytalloc_Object
 
@@ -126,6 +134,8 @@ use a generic VoidPtr Python type, which just provides an opaque object in
 Python. The caller is responsible for incrementing the talloc reference count before calling
 this function - it will dereference the talloc pointer when it is garbage collected.
 
+This function is only available on Python 2.
+
 Debug function for talloc in Python
 -----------------------------------
 
index 89a093b1cefdfcefe736c80ad967ec8a1e9e27ac..0af7c054507eab6e6a5ac8311c05d5a0f2d3ac27 100644 (file)
@@ -97,6 +97,8 @@ _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_
        return (PyObject *)ret;
 }
 
+#if PY_MAJOR_VERSION < 3
+
 static void py_cobject_talloc_free(void *ptr)
 {
        talloc_free(ptr);
@@ -110,6 +112,8 @@ _PUBLIC_ PyObject *pytalloc_CObject_FromTallocPtr(void *ptr)
        return PyCObject_FromVoidPtr(ptr, py_cobject_talloc_free);
 }
 
+#endif
+
 _PUBLIC_ int pytalloc_Check(PyObject *obj)
 {
        PyTypeObject *tp = pytalloc_GetObjectType();
index 2eaa7c31fb266cb508d958db7bbfcf3f50a9553f..f66b4e59b524bd04e97ce6ebe511a6d560351e7d 100644 (file)
@@ -104,25 +104,56 @@ static PyTypeObject DObject_Type = {
        .tp_doc = "test talloc object that calls a function when underlying data is freed\n",
 };
 
-#define MODULE_DOC "Test utility module for pytalloc"
+#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "_test_pytalloc",
+    .m_doc = PyDoc_STR("Test utility module for pytalloc"),
+    .m_size = -1,
+    .m_methods = test_talloc_methods,
+};
+#endif
 
-void init_test_pytalloc(void);
-void init_test_pytalloc(void)
+static PyObject *module_init(void);
+static PyObject *module_init(void)
 {
        PyObject *m;
 
        DObject_Type.tp_base = pytalloc_GetObjectType();
        if (PyType_Ready(&DObject_Type) < 0) {
-               return;
+               return NULL;
        }
 
+#if PY_MAJOR_VERSION >= 3
+       m = PyModule_Create(&moduledef);
+#else
        m = Py_InitModule3("_test_pytalloc", test_talloc_methods, MODULE_DOC);
+#endif
 
        if (m == NULL) {
-               return;
+               return NULL;
        }
 
        Py_INCREF(&DObject_Type);
        Py_INCREF(DObject_Type.tp_base);
        PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
+
+       return m;
+}
+
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit__test_pytalloc(void);
+PyMODINIT_FUNC PyInit__test_pytalloc(void)
+{
+       return module_init();
+}
+#else
+void init_test_pytalloc(void);
+void init_test_pytalloc(void)
+{
+       module_init();
 }
+#endif
index 961bfcb51b6bb98ac20d74320b4d2c3c811866f6..a6133735a98df8b531dbb7c3b5413a3a8d155a46 100644 (file)
@@ -78,6 +78,9 @@ class TallocComparisonTests(unittest.TestCase):
 
     def test_compare_different_types(self):
         # object comparison falls back to comparing types
+        if sys.version_info >= (3, 0):
+            # In Python 3, types are unorderable -- nothing to test
+            return
         if talloc.Object < _test_pytalloc.DObject:
             obj1 = _test_pytalloc.new()
             obj2 = _test_pytalloc.DObject(dummy_func)
index 136798839840c33d84a1201e09c5683c9ed96925..3bc932e93cf95422119dea954afd0be29e540531 100644 (file)
@@ -60,9 +60,7 @@ def configure(conf):
 
     if not conf.env.disable_python:
         # also disable if we don't have the python libs installed
-        conf.find_program('python', var='PYTHON')
-        conf.check_tool('python')
-        conf.check_python_version((2,4,2))
+        conf.SAMBA_CHECK_PYTHON(mandatory=False, version=(2,4,2))
         conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
         if not conf.env.HAVE_PYTHON_H:
             Logs.warn('Disabling pytalloc-util as python devel libs not found')
@@ -118,7 +116,9 @@ def build(bld):
                           manpages='man/talloc.3')
 
     if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL') and not bld.env.disable_python:
-        bld.SAMBA_LIBRARY('pytalloc-util',
+        name = bld.pyembed_libname('pytalloc-util')
+
+        bld.SAMBA_LIBRARY(name,
             source='pytalloc_util.c',
             public_deps='talloc',
             pyembed=True,
@@ -132,7 +132,7 @@ def build(bld):
             )
         bld.SAMBA_PYTHON('pytalloc',
                          'pytalloc.c',
-                         deps='talloc pytalloc-util',
+                         deps='talloc ' + name,
                          enabled=True,
                          realname='talloc.so')