Py3: __cmp__ is gone, __bool__ instead of __nonzero__
authorLisandro Dalcin <dalcinl@gmail.com>
Wed, 28 Apr 2010 15:04:13 +0000 (12:04 -0300)
committerLisandro Dalcin <dalcinl@gmail.com>
Wed, 28 Apr 2010 15:04:13 +0000 (12:04 -0300)
Cython/Compiler/AnalysedTreeTransforms.py
Cython/Compiler/TypeSlots.py
tests/run/autotestdict.pyx
tests/run/type_slots_nonzero_bool.pyx [new file with mode: 0644]

index 6c4e1182baf3458d13b365a1fe912a17337a0528..18ca5bd8ad240eaefd622044f8bbde08da5fe835 100644 (file)
@@ -11,7 +11,8 @@ import Symtab
 class AutoTestDictTransform(ScopeTrackingTransform):
     # Handles autotestdict directive
 
-    blacklist = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__',
+    blacklist = ['__cinit__', '__dealloc__', '__richcmp__', 
+                 '__nonzero__', '__bool__',
                  '__len__', '__contains__']
 
     def visit_ModuleNode(self, node):
index 232c51d263102949e7bf0275309eb8ff5515d451..ee02c17ae980c014955564c84f0d9ab47c5d4c6f 100644 (file)
@@ -126,16 +126,17 @@ class SlotDescriptor(object):
     #  slot_name    string           Member name of the slot in the type object
     #  is_initialised_dynamically    Is initialised by code in the module init function
     #  flag                          Py_TPFLAGS_XXX value indicating presence of slot
-    #  py3k                          Indicates presence of slot in Python 3
+    #  py3                           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.)
+    #  ifdef                         Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.)
 
-    def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True, ifdef = None):
+    def __init__(self, slot_name, dynamic=0,
+                 flag=None, py3=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.py3 = py3
+        self.py2 = py2
         self.ifdef = ifdef
 
     def generate(self, scope, code):
@@ -144,26 +145,26 @@ class SlotDescriptor(object):
         else:
             value = self.slot_code(scope)
         flag = self.flag
-        py3k = self.py3k
-        py2  = self.py2
+        py3 = self.py3
+        py2 = self.py2
         if self.ifdef:
             code.putln("#if %s" % self.ifdef)
         else:
-            if not py3k:
+            if not py3:
                 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 py3k == '<RESERVED>':
+        if py3 == '<RESERVED>':
             code.putln("#if PY_MAJOR_VERSION >= 3")
             code.putln("0, /*reserved*/")
             code.putln("#else")
 
         code.putln("%s, /*%s*/" % (value, self.slot_name))
-        if py3k == '<RESERVED>':
+        if py3 == '<RESERVED>':
             code.putln("#endif")
-        if flag or (not py3k or not py2) or self.ifdef:
+        if flag or (not py3 or not py2) or self.ifdef:
             code.putln("#endif")
 
     # Some C implementations have trouble statically 
@@ -188,8 +189,8 @@ class FixedSlot(SlotDescriptor):
     #
     #  value        string
     
-    def __init__(self, slot_name, value, py3k=True, py2=True, ifdef=None):
-        SlotDescriptor.__init__(self, slot_name, py3k=py3k, py2=py2, ifdef=ifdef)
+    def __init__(self, slot_name, value, flag=None, py3=True, py2=True, ifdef=None):
+        SlotDescriptor.__init__(self, slot_name, flag=flag, py3=py3, py2=py2, ifdef=ifdef)
         self.value = value
     
     def slot_code(self, scope):
@@ -199,8 +200,8 @@ class FixedSlot(SlotDescriptor):
 class EmptySlot(FixedSlot):
     #  Descriptor for a type slot whose value is always 0.
     
-    def __init__(self, slot_name, py3k=True, py2=True, ifdef=None):
-        FixedSlot.__init__(self, slot_name, "0", py3k=py3k, py2=py2, ifdef=ifdef)
+    def __init__(self, slot_name, flag=None, py3=True, py2=True, ifdef=None):
+        FixedSlot.__init__(self, slot_name, "0", flag=flag, py3=py3, py2=py2, ifdef=ifdef)
 
 
 class MethodSlot(SlotDescriptor):
@@ -208,22 +209,31 @@ class MethodSlot(SlotDescriptor):
     #
     #  signature    Signature
     #  method_name  string           The __xxx__ name of the method
-    #  default      string or None   Default value of the slot
+    #  alternatives [string]         Alternative list of __xxx__ names for the method
     
-    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)
+    def __init__(self, signature, slot_name, method_name, fallback=None, 
+                 flag=None, py3=True, py2=True, ifdef=None):
+        SlotDescriptor.__init__(self, slot_name, flag=flag, py3=py3, py2=py2, ifdef=ifdef)
         self.signature = signature
         self.slot_name = slot_name
         self.method_name = method_name
-        self.default = default
+        self.alternatives = []
         method_name_to_slot[method_name] = self
+        #
+        if fallback:
+            self.alternatives.append(fallback)
+        for alt in (self.py2, self.py3):
+            if isinstance(alt, (tuple, list)):
+                slot_name, method_name = alt
+                self.alternatives.append(method_name)
+                method_name_to_slot[method_name] = self
 
     def slot_code(self, scope):
         entry = scope.lookup_here(self.method_name)
         if entry and entry.func_cname:
             return entry.func_cname
-        if self.default is not None:
-            entry = scope.lookup_here(self.default)
+        for method_name in self.alternatives:
+            entry = scope.lookup_here(method_name)
             if entry and entry.func_cname:
                 return entry.func_cname
         return "0"
@@ -235,8 +245,8 @@ class InternalMethodSlot(SlotDescriptor):
     #
     #  slot_name    string           Member name of the slot in the type object
 
-    def __init__(self, slot_name, py2 = True):
-        SlotDescriptor.__init__(self, slot_name, py2 = py2)
+    def __init__(self, slot_name, **kargs):
+        SlotDescriptor.__init__(self, slot_name, **kargs)
 
     def slot_code(self, scope):
         return scope.mangle_internal(self.slot_name)
@@ -246,8 +256,8 @@ class GCDependentSlot(InternalMethodSlot):
     #  Descriptor for a slot whose value depends on whether
     #  the type participates in GC.
     
-    def __init__(self, slot_name):
-        InternalMethodSlot.__init__(self, slot_name)
+    def __init__(self, slot_name, **kargs):
+        InternalMethodSlot.__init__(self, slot_name, **kargs)
     
     def slot_code(self, scope):
         if not scope.needs_gc():
@@ -267,8 +277,8 @@ class GCDependentSlot(InternalMethodSlot):
 class ConstructorSlot(InternalMethodSlot):
     #  Descriptor for tp_new and tp_dealloc.
     
-    def __init__(self, slot_name, method):
-        InternalMethodSlot.__init__(self, slot_name)
+    def __init__(self, slot_name, method, **kargs):
+        InternalMethodSlot.__init__(self, slot_name, **kargs)
         self.method = method
     
     def slot_code(self, scope):
@@ -294,8 +304,8 @@ class SyntheticSlot(InternalMethodSlot):
     #  alternative default value will be placed in the type
     #  slot.
     
-    def __init__(self, slot_name, user_methods, default_value, py2 = True):
-        InternalMethodSlot.__init__(self, slot_name, py2 = py2)
+    def __init__(self, slot_name, user_methods, default_value, **kargs):
+        InternalMethodSlot.__init__(self, slot_name, **kargs)
         self.user_methods = user_methods
         self.default_value = default_value
     
@@ -550,32 +560,32 @@ PyNumberMethods = (
     MethodSlot(binaryfunc, "nb_add", "__add__"),
     MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
     MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
-    MethodSlot(binaryfunc, "nb_divide", "__div__", py3k = False),
+    MethodSlot(binaryfunc, "nb_divide", "__div__", py3 = False),
     MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
     MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
     MethodSlot(ternaryfunc, "nb_power", "__pow__"),
     MethodSlot(unaryfunc, "nb_negative", "__neg__"),
     MethodSlot(unaryfunc, "nb_positive", "__pos__"),
     MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
-    MethodSlot(inquiry, "nb_nonzero", "__nonzero__"),
+    MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")),
     MethodSlot(unaryfunc, "nb_invert", "__invert__"),
     MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
     MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
     MethodSlot(binaryfunc, "nb_and", "__and__"),
     MethodSlot(binaryfunc, "nb_xor", "__xor__"),
     MethodSlot(binaryfunc, "nb_or", "__or__"),
-    EmptySlot("nb_coerce", py3k = False),
-    MethodSlot(unaryfunc, "nb_int", "__int__", default="__long__"),
-    MethodSlot(unaryfunc, "nb_long", "__long__", default="__int__", py3k = "<RESERVED>"),
+    EmptySlot("nb_coerce", py3 = False),
+    MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"),
+    MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"),
     MethodSlot(unaryfunc, "nb_float", "__float__"),
-    MethodSlot(unaryfunc, "nb_oct", "__oct__", py3k = False),
-    MethodSlot(unaryfunc, "nb_hex", "__hex__", py3k = False),
+    MethodSlot(unaryfunc, "nb_oct", "__oct__", py3 = False),
+    MethodSlot(unaryfunc, "nb_hex", "__hex__", py3 = False),
     
     # Added in release 2.0
     MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"),
     MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"),
     MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"),
-    MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", py3k = False),
+    MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", py3 = False),
     MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
     MethodSlot(ternaryfunc, "nb_inplace_power", "__ipow__"), # NOT iternaryfunc!!!
     MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
@@ -615,10 +625,10 @@ PyMappingMethods = (
 )
 
 PyBufferProcs = (
-    MethodSlot(getreadbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3k = False),
-    MethodSlot(getwritebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3k = False),
-    MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3k = False),
-    MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3k = False),
+    MethodSlot(getreadbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False),
+    MethodSlot(getwritebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False),
+    MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3 = False),
+    MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False),
 
     MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"),
     MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000")
@@ -637,7 +647,7 @@ slot_table = (
     EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
     EmptySlot("tp_getattr"),
     EmptySlot("tp_setattr"),
-    MethodSlot(cmpfunc, "tp_compare", "__cmp__"),
+    MethodSlot(cmpfunc, "tp_compare", "__cmp__", py3 = '<RESERVED>'),
     MethodSlot(reprfunc, "tp_repr", "__repr__"),
     
     SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
index 2f8bc71196aabbc3cc4fe38c4cdd4f13529f32e0..51e347eeded4ab54fe3652c47c0af51bbed954bb 100644 (file)
@@ -126,4 +126,20 @@ cdef class MyCdefClass:
         False
         """
 
+cdef class MyOtherCdefClass:
+    """
+    Needs no hack
+    
+    >>> True
+    True
+    """
+
+    def __bool__(self):
+        """
+        Should not be included, as it can't be looked up with getattr in Py 2
+
+        >>> True
+        False
+        """
+
 cdeffunc()
diff --git a/tests/run/type_slots_nonzero_bool.pyx b/tests/run/type_slots_nonzero_bool.pyx
new file mode 100644 (file)
index 0000000..a9dd791
--- /dev/null
@@ -0,0 +1,43 @@
+__doc__ = """
+
+>>> not not BoolA(0)
+False
+>>> not not BoolA(1)
+True
+
+>>> not not BoolB(0)
+False
+>>> not not BoolB(1)
+True
+
+>>> not not BoolX(0)
+False
+>>> not not BoolX(1)
+True
+
+>>> not not BoolY(0)
+False
+>>> not not BoolY(1)
+True
+
+"""
+
+cdef class BoolA:
+    cdef bint value
+    def __cinit__(self, bint value):
+        self.value = value
+    def __nonzero__(self):
+        return self.value
+
+cdef class BoolB:
+    cdef bint value
+    def __cinit__(self, bint value):
+        self.value = value
+    def __bool__(self):
+        return self.value
+
+cdef class BoolX(BoolA):
+    pass
+
+cdef class BoolY(BoolB):
+    pass