From 509b419f998ce9e89a4d877b411dae2d57a0730b Mon Sep 17 00:00:00 2001 From: Dag Sverre Seljebotn Date: Thu, 4 Sep 2008 13:25:09 +0200 Subject: [PATCH] Buffers: Better Py2.6 support (ticket 62) --- Cython/Compiler/Buffer.py | 11 +++++++++-- Cython/Compiler/ModuleNode.py | 4 ++++ Cython/Compiler/TypeSlots.py | 33 ++++++++++++++++++--------------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Cython/Compiler/Buffer.py b/Cython/Compiler/Buffer.py index ea5f167f..41b5ee11 100644 --- a/Cython/Compiler/Buffer.py +++ b/Cython/Compiler/Buffer.py @@ -566,6 +566,9 @@ def buffer_type_checker(dtype, code): return funcname def use_py2_buffer_functions(env): + # Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2. + # For >= 2.6 we do double mode -- use the new buffer interface on objects + # which has the right tp_flags set, but emulation otherwise. codename = "PyObject_GetBuffer" # just a representative unique key # Search all types for __getbuffer__ overloads @@ -586,8 +589,12 @@ def use_py2_buffer_functions(env): find_buffer_types(env) code = dedent(""" - #if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER) + #if PY_MAJOR_VERSION < 3 static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) { + #if PY_VERSION_HEX >= 0x02060000 + if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER) + return PyObject_GetBuffer(obj, view, flags); + #endif """) if len(types) > 0: clause = "if" @@ -623,7 +630,7 @@ def use_py2_buffer_functions(env): """) env.use_utility_code([dedent("""\ - #if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER) + #if PY_MAJOR_VERSION < 3 static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags); static void __Pyx_ReleaseBuffer(Py_buffer *view); #else diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index f2987cec..6beaa6fa 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -461,6 +461,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): code.putln(" #define Py_TPFLAGS_HAVE_INDEX 0") code.putln("#endif") + code.putln("#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)") + code.putln(" #define Py_TPFLAGS_HAVE_NEWBUFFER 0") + code.putln("#endif") + code.putln("#if PY_MAJOR_VERSION >= 3") code.putln(" #define PyBaseString_Type PyUnicode_Type") code.putln(" #define PyString_Type PyBytes_Type") diff --git a/Cython/Compiler/TypeSlots.py b/Cython/Compiler/TypeSlots.py index a5898c97..d62f1cc2 100644 --- a/Cython/Compiler/TypeSlots.py +++ b/Cython/Compiler/TypeSlots.py @@ -127,13 +127,15 @@ class SlotDescriptor: # flag Py_TPFLAGS_XXX value indicating presence of slot # py3k Indicates presence of slot in Python 3 # py2 Indicates presence of slot in Python 2 + # ifdef Full #ifdef string that slot is wrapped in. Using this causes py3k, py2 and flags to be ignored.) - def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True): + def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True, ifdef = None): self.slot_name = slot_name self.is_initialised_dynamically = dynamic self.flag = flag self.py3k = py3k self.py2 = py2 + self.ifdef = ifdef def generate(self, scope, code): if self.is_initialised_dynamically: @@ -143,16 +145,17 @@ class SlotDescriptor: flag = self.flag py3k = self.py3k py2 = self.py2 - if not py3k: - code.putln("#if PY_MAJOR_VERSION < 3") - elif not py2: - code.putln("#if PY_MAJOR_VERSION >= 3") - if flag: - code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag) + if self.ifdef: + code.putln("#if %s" % self.ifdef) + else: + if not py3k: + code.putln("#if PY_MAJOR_VERSION < 3") + elif not py2: + code.putln("#if PY_MAJOR_VERSION >= 3") + if flag: + code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag) code.putln("%s, /*%s*/" % (value, self.slot_name)) - if flag: - code.putln("#endif") - if not py3k or not py2: + if flag or (not py3k or not py2) or self.ifdef: code.putln("#endif") # Some C implementations have trouble statically @@ -199,8 +202,8 @@ class MethodSlot(SlotDescriptor): # method_name string The __xxx__ name of the method # default string or None Default value of the slot - def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True): - SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2) + def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True, ifdef=None): + SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2, ifdef=ifdef) self.signature = signature self.slot_name = slot_name self.method_name = method_name @@ -296,7 +299,7 @@ class TypeFlagsSlot(SlotDescriptor): # Descriptor for the type flags slot. def slot_code(self, scope): - value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE" + value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER" if scope.needs_gc(): value += "|Py_TPFLAGS_HAVE_GC" return value @@ -609,8 +612,8 @@ PyBufferProcs = ( MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3k = False), MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3k = False), - MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"), - MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"), + MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"), + MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000") ) #------------------------------------------------------------------------------------------ -- 2.26.2