Commit 6ae02221 authored by Stefan Behnel's avatar Stefan Behnel

extended test case to include test code for ticket #3

parent c95fe868
# mode: run
# ticket: 561 # ticket: 561
# ticket: 3
# The patch in #561 changes code generation for most special methods # The patch in #561 changes code generation for most special methods
# to remove the Cython-generated wrapper and let PyType_Ready() # to remove the Cython-generated wrapper and let PyType_Ready()
# generate its own wrapper. (This wrapper would be used, for instance, # generate its own wrapper. (This wrapper would be used, for instance,
...@@ -12,13 +15,117 @@ ...@@ -12,13 +15,117 @@
# special_methods_T561_py3.pyx for tests of the differences between # special_methods_T561_py3.pyx for tests of the differences between
# Python 2 and 3. # Python 2 and 3.
# Regarding ticket 3, we should additionally test that unbound method
# calls to these special methods (e.g. ExtType.__init__()) do not use
# a runtime lookup indirection.
import sys import sys
__doc__ = u""" __doc__ = u"""
>>> # If you define either setitem or delitem, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> si_setitem = SetItem().__setitem__
>>> si_setitem('foo', 'bar')
SetItem setitem 'foo' 'bar'
>>> si_delitem = SetItem().__delitem__
>>> si_delitem('foo')
Traceback (most recent call last):
...
NotImplementedError: Subscript deletion not supported by special_methods_T561.SetItem
>>> di_setitem = DelItem().__setitem__
>>> di_setitem('foo', 'bar')
Traceback (most recent call last):
...
NotImplementedError: Subscript assignment not supported by special_methods_T561.DelItem
>>> di_delitem = DelItem().__delitem__
>>> di_delitem('foo')
DelItem delitem 'foo'
>>> sdi_setitem = SetDelItem().__setitem__
>>> sdi_setitem('foo', 'bar')
SetDelItem setitem 'foo' 'bar'
>>> sdi_delitem = SetDelItem().__delitem__
>>> sdi_delitem('foo')
SetDelItem delitem 'foo'
>>> g01 = object.__getattribute__(GetAttr(), '__getattribute__')
>>> g01('attr')
GetAttr getattr 'attr'
>>> g10 = object.__getattribute__(GetAttribute(), '__getattr__')
Traceback (most recent call last):
...
AttributeError: 'special_methods_T561.GetAttribute' object has no attribute '__getattr__'
>>> g11 = object.__getattribute__(GetAttribute(), '__getattribute__')
>>> g11('attr')
GetAttribute getattribute 'attr'
>>> # If you define either setattr or delattr, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> sa_setattr = SetAttr().__setattr__
>>> sa_setattr('foo', 'bar')
SetAttr setattr 'foo' 'bar'
>>> sa_delattr = SetAttr().__delattr__
>>> sa_delattr('foo')
Traceback (most recent call last):
...
AttributeError: 'special_methods_T561.SetAttr' object has no attribute 'foo'
>>> da_setattr = DelAttr().__setattr__
>>> da_setattr('foo', 'bar')
Traceback (most recent call last):
...
AttributeError: 'special_methods_T561.DelAttr' object has no attribute 'foo'
>>> da_delattr = DelAttr().__delattr__
>>> da_delattr('foo')
DelAttr delattr 'foo'
>>> sda_setattr = SetDelAttr().__setattr__
>>> sda_setattr('foo', 'bar')
SetDelAttr setattr 'foo' 'bar'
>>> sda_delattr = SetDelAttr().__delattr__
>>> sda_delattr('foo')
SetDelAttr delattr 'foo'
>>> # If you define either set or delete, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> s_set = Set().__set__
>>> s_set('instance', 'val')
Set set 'instance' 'val'
>>> s_delete = Set().__delete__
>>> s_delete('instance')
Traceback (most recent call last):
...
NotImplementedError: __delete__
>>> d_set = Delete().__set__
>>> d_set('instance', 'val')
Traceback (most recent call last):
...
NotImplementedError: __set__
>>> d_delete = Delete().__delete__
>>> d_delete('instance')
Delete delete 'instance'
>>> sd_set = SetDelete().__set__
>>> sd_set('instance', 'val')
SetDelete set 'instance' 'val'
>>> sd_delete = SetDelete().__delete__
>>> sd_delete('instance')
SetDelete delete 'instance'
>>> # If you define __long__, you get a wrapper object for __int__.
>>> # (This behavior is unchanged by #561.)
>>> Li = Long().__int__
>>> Li()
Long __long__
"""
if sys.version_info >= (2,5):
__doc__ += u"""\
>>> vs0 = VerySpecial(0)
VS __init__ 0
>>> vs0_index = vs0.__index__
>>> vs0_index()
VS __index__ 0
"""
cdef class VerySpecial:
"""
>>> vs0 = VerySpecial(0) >>> vs0 = VerySpecial(0)
VS __init__ 0 VS __init__ 0
>>> vs1 = VerySpecial(1) >>> vs1 = VerySpecial(1)
VS __init__ 1 VS __init__ 1
>>> vs0_add = vs0.__add__ >>> vs0_add = vs0.__add__
>>> vs0_add(vs1) >>> vs0_add(vs1)
VS __add__ 0 1 VS __add__ 0 1
...@@ -114,8 +221,9 @@ __doc__ = u""" ...@@ -114,8 +221,9 @@ __doc__ = u"""
>>> vs0_itruediv = vs0.__itruediv__ >>> vs0_itruediv = vs0.__itruediv__
>>> vs0_itruediv(vs1) >>> vs0_itruediv(vs1)
VS __itruediv__ 0 /= 1 VS __itruediv__ 0 /= 1
>>> # If you define an arithmetic method, you get wrapper objects for
>>> # the reversed version as well. (This behavior is unchanged by #561.) # If you define an arithmetic method, you get wrapper objects for
# the reversed version as well. (This behavior is unchanged by #561.)
>>> vs0_radd = vs0.__radd__ >>> vs0_radd = vs0.__radd__
>>> vs0_radd(vs1) >>> vs0_radd(vs1)
VS __add__ 1 0 VS __add__ 1 0
...@@ -166,30 +274,6 @@ __doc__ = u""" ...@@ -166,30 +274,6 @@ __doc__ = u"""
>>> vs0_len() >>> vs0_len()
VS __len__ 0 VS __len__ 0
0 0
>>> # If you define either setitem or delitem, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> si_setitem = SetItem().__setitem__
>>> si_setitem('foo', 'bar')
SetItem setitem 'foo' 'bar'
>>> si_delitem = SetItem().__delitem__
>>> si_delitem('foo')
Traceback (most recent call last):
...
NotImplementedError: Subscript deletion not supported by special_methods_T561.SetItem
>>> di_setitem = DelItem().__setitem__
>>> di_setitem('foo', 'bar')
Traceback (most recent call last):
...
NotImplementedError: Subscript assignment not supported by special_methods_T561.DelItem
>>> di_delitem = DelItem().__delitem__
>>> di_delitem('foo')
DelItem delitem 'foo'
>>> sdi_setitem = SetDelItem().__setitem__
>>> sdi_setitem('foo', 'bar')
SetDelItem setitem 'foo' 'bar'
>>> sdi_delitem = SetDelItem().__delitem__
>>> sdi_delitem('foo')
SetDelItem delitem 'foo'
>>> vs0_repr = vs0.__repr__ >>> vs0_repr = vs0.__repr__
>>> vs0_repr() >>> vs0_repr()
VS __repr__ 0 VS __repr__ 0
...@@ -203,44 +287,11 @@ __doc__ = u""" ...@@ -203,44 +287,11 @@ __doc__ = u"""
>>> vs0_str = vs0.__str__ >>> vs0_str = vs0.__str__
>>> vs0_str() >>> vs0_str()
VS __str__ 0 VS __str__ 0
>>> g01 = object.__getattribute__(GetAttr(), '__getattribute__')
>>> g01('attr') # If you define __richcmp__, you get all of __lt__, __le__,
GetAttr getattr 'attr' # __eq__, __ne__, __gt__, __ge__ (this behavior is unchanged by #561).
>>> g10 = object.__getattribute__(GetAttribute(), '__getattr__') # (you don't get a __richcmp__ method, because it doesn't have a
Traceback (most recent call last): # Python signature)
...
AttributeError: 'special_methods_T561.GetAttribute' object has no attribute '__getattr__'
>>> g11 = object.__getattribute__(GetAttribute(), '__getattribute__')
>>> g11('attr')
GetAttribute getattribute 'attr'
>>> # If you define either setattr or delattr, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> sa_setattr = SetAttr().__setattr__
>>> sa_setattr('foo', 'bar')
SetAttr setattr 'foo' 'bar'
>>> sa_delattr = SetAttr().__delattr__
>>> sa_delattr('foo')
Traceback (most recent call last):
...
AttributeError: 'special_methods_T561.SetAttr' object has no attribute 'foo'
>>> da_setattr = DelAttr().__setattr__
>>> da_setattr('foo', 'bar')
Traceback (most recent call last):
...
AttributeError: 'special_methods_T561.DelAttr' object has no attribute 'foo'
>>> da_delattr = DelAttr().__delattr__
>>> da_delattr('foo')
DelAttr delattr 'foo'
>>> sda_setattr = SetDelAttr().__setattr__
>>> sda_setattr('foo', 'bar')
SetDelAttr setattr 'foo' 'bar'
>>> sda_delattr = SetDelAttr().__delattr__
>>> sda_delattr('foo')
SetDelAttr delattr 'foo'
>>> # If you define __richcmp__, you get all of __lt__, __le__,
>>> # __eq__, __ne__, __gt__, __ge__ (this behavior is unchanged by #561).
>>> # (you don't get a __richcmp__ method, because it doesn't have a
>>> # Python signature)
>>> vs0_lt = vs0.__lt__ >>> vs0_lt = vs0.__lt__
>>> vs0_lt(vs1) >>> vs0_lt(vs1)
VS richcmp 0 1 (kind=0) VS richcmp 0 1 (kind=0)
...@@ -265,50 +316,14 @@ __doc__ = u""" ...@@ -265,50 +316,14 @@ __doc__ = u"""
>>> vs0_next = vs0.__next__ >>> vs0_next = vs0.__next__
>>> vs0_next() >>> vs0_next()
VS next/__next__ 0 VS next/__next__ 0
>>> vs0_get = vs0.__get__ >>> vs0_get = vs0.__get__
>>> vs0_get('instance', 'owner') >>> vs0_get('instance', 'owner')
VS __get__ 0 'instance' 'owner' VS __get__ 0 'instance' 'owner'
>>> # If you define either set or delete, you get wrapper objects
>>> # for both methods. (This behavior is unchanged by #561.)
>>> s_set = Set().__set__
>>> s_set('instance', 'val')
Set set 'instance' 'val'
>>> s_delete = Set().__delete__
>>> s_delete('instance')
Traceback (most recent call last):
...
NotImplementedError: __delete__
>>> d_set = Delete().__set__
>>> d_set('instance', 'val')
Traceback (most recent call last):
...
NotImplementedError: __set__
>>> d_delete = Delete().__delete__
>>> d_delete('instance')
Delete delete 'instance'
>>> sd_set = SetDelete().__set__
>>> sd_set('instance', 'val')
SetDelete set 'instance' 'val'
>>> sd_delete = SetDelete().__delete__
>>> sd_delete('instance')
SetDelete delete 'instance'
>>> vs0_init = vs0.__init__ >>> vs0_init = vs0.__init__
>>> vs0_init(0) >>> vs0_init(0)
VS __init__ 0 VS __init__ 0
>>> # If you define __long__, you get a wrapper object for __int__. """
>>> # (This behavior is unchanged by #561.)
>>> Li = Long().__int__
>>> Li()
Long __long__
"""
if sys.version_info >= (2,5):
__doc__ += u"""\
>>> vs0_index = vs0.__index__
>>> vs0_index()
VS __index__ 0
"""
cdef class VerySpecial:
cdef readonly int value cdef readonly int value
def __init__(self, v): def __init__(self, v):
...@@ -552,3 +567,359 @@ cdef class GetAttrGetItemRedirect: ...@@ -552,3 +567,359 @@ cdef class GetAttrGetItemRedirect:
if key == 'attr': if key == 'attr':
return getattr(self, key) return getattr(self, key)
return ('item', self.obj) return ('item', self.obj)
# test unbound method usage in subtypes
cdef class VerySpecialSubType(VerySpecial):
"""
>>> vs0 = VerySpecialSubType(0)
VS __init__ 0
>>> vs1 = VerySpecialSubType(1)
VS __init__ 1
>>> vs0_add = vs0.__add__
>>> vs0_add(vs1)
VS __add__ 0 1
>>> vs0_sub = vs0.__sub__
>>> vs0_sub(vs1)
VS __sub__ 0 1
>>> vs0_mul = vs0.__mul__
>>> vs0_mul(vs1)
VS __mul__ 0 1
>>> vs0_mod = vs0.__mod__
>>> vs0_mod(vs1)
VS __mod__ 0 1
>>> vs0_divmod = vs0.__divmod__
>>> vs0_divmod(vs1)
VS __divmod__ 0 1
>>> vs0_pow = vs0.__pow__
>>> vs0_pow(vs1)
VS __pow__ pow(0, 1, None)
>>> vs0_pow(vs1, 13)
VS __pow__ pow(0, 1, 13)
>>> vs0_neg = vs0.__neg__
>>> vs0_neg()
VS __neg__ 0
>>> vs0_pos = vs0.__pos__
>>> vs0_pos()
VS __pos__ 0
>>> vs0_abs = vs0.__abs__
>>> vs0_abs()
VS __abs__ 0
>>> vs0_invert = vs0.__invert__
>>> vs0_invert()
VS __invert__ 0
>>> vs0_lshift = vs0.__lshift__
>>> vs0_lshift(vs1)
VS __lshift__ 0 << 1
>>> vs0_rshift = vs0.__rshift__
>>> vs0_rshift(vs1)
VS __rshift__ 0 >> 1
>>> vs0_and = vs0.__and__
>>> vs0_and(vs1)
VS __and__ 0 & 1
>>> vs0_xor = vs0.__xor__
>>> vs0_xor(vs1)
VS __xor__ 0 ^ 1
>>> vs0_or = vs0.__or__
>>> vs0_or(vs1)
VS __or__ 0 | 1
>>> vs0_int = vs0.__int__
>>> vs0_int()
VS __int__ 0
>>> vs0_float = vs0.__float__
>>> vs0_float()
VS __float__ 0
>>> vs0_iadd = vs0.__iadd__
>>> vs0_iadd(vs1)
VS __iadd__ 0 += 1
>>> vs0_isub = vs0.__isub__
>>> vs0_isub(vs1)
VS __isub__ 0 -= 1
>>> vs0_imul = vs0.__imul__
>>> vs0_imul(vs1)
VS __imul__ 0 *= 1
>>> vs0_imod = vs0.__imod__
>>> vs0_imod(vs1)
VS __imod__ 0 %= 1
>>> vs0_ipow = vs0.__ipow__
>>> vs0_ipow(vs1)
VS __ipow__ 0 1
>>> vs0_ilshift = vs0.__ilshift__
>>> vs0_ilshift(vs1)
VS __ilshift__ 0 <<= 1
>>> vs0_irshift = vs0.__irshift__
>>> vs0_irshift(vs1)
VS __irshift__ 0 >>= 1
>>> vs0_iand = vs0.__iand__
>>> vs0_iand(vs1)
VS __iand__ 0 &= 1
>>> vs0_ixor = vs0.__ixor__
>>> vs0_ixor(vs1)
VS __ixor__ 0 ^= 1
>>> vs0_ior = vs0.__ior__
>>> vs0_ior(vs1)
VS __ior__ 0 |= 1
>>> vs0_floordiv = vs0.__floordiv__
>>> vs0_floordiv(vs1)
VS __floordiv__ 0 / 1
>>> vs0_truediv = vs0.__truediv__
>>> vs0_truediv(vs1)
VS __truediv__ 0 / 1
>>> vs0_ifloordiv = vs0.__ifloordiv__
>>> vs0_ifloordiv(vs1)
VS __ifloordiv__ 0 /= 1
>>> vs0_itruediv = vs0.__itruediv__
>>> vs0_itruediv(vs1)
VS __itruediv__ 0 /= 1
# If you define an arithmetic method, you get wrapper objects for
# the reversed version as well. (This behavior is unchanged by #561.)
>>> vs0_radd = vs0.__radd__
>>> vs0_radd(vs1)
VS __add__ 1 0
>>> vs0_rsub = vs0.__rsub__
>>> vs0_rsub(vs1)
VS __sub__ 1 0
>>> vs0_rmul = vs0.__rmul__
>>> vs0_rmul(vs1)
VS __mul__ 1 0
>>> vs0_rmod = vs0.__rmod__
>>> vs0_rmod(vs1)
VS __mod__ 1 0
>>> vs0_rdivmod = vs0.__rdivmod__
>>> vs0_rdivmod(vs1)
VS __divmod__ 1 0
>>> vs0_rpow = vs0.__rpow__
>>> vs0_rpow(vs1)
VS __pow__ pow(1, 0, None)
>>> vs0_rlshift = vs0.__rlshift__
>>> vs0_rlshift(vs1)
VS __lshift__ 1 << 0
>>> vs0_rrshift = vs0.__rrshift__
>>> vs0_rrshift(vs1)
VS __rshift__ 1 >> 0
>>> vs0_rand = vs0.__rand__
>>> vs0_rand(vs1)
VS __and__ 1 & 0
>>> vs0_rxor = vs0.__rxor__
>>> vs0_rxor(vs1)
VS __xor__ 1 ^ 0
>>> vs0_ror = vs0.__ror__
>>> vs0_ror(vs1)
VS __or__ 1 | 0
>>> vs0_rfloordiv = vs0.__rfloordiv__
>>> vs0_rfloordiv(vs1)
VS __floordiv__ 1 / 0
>>> vs0_rtruediv = vs0.__rtruediv__
>>> vs0_rtruediv(vs1)
VS __truediv__ 1 / 0
>>> vs0_getitem = vs0.__getitem__
>>> vs0_getitem('foo')
VS __getitem__ 0['foo']
>>> vs0_contains = vs0.__contains__
>>> vs0_contains(vs1)
VS __contains__ 0 1
False
>>> vs0_len = vs0.__len__
>>> vs0_len()
VS __len__ 0
0
>>> vs0_repr = vs0.__repr__
>>> vs0_repr()
VS __repr__ 0
>>> vs0_hash = vs0.__hash__
>>> vs0_hash()
VS __hash__ 0
1000
>>> vs0_call = vs0.__call__
>>> vs0_call(vs1)
VS __call__ 0(1)
>>> vs0_str = vs0.__str__
>>> vs0_str()
VS __str__ 0
>>> vs0_lt = vs0.__lt__
>>> vs0_lt(vs1)
VS richcmp 0 1 (kind=0)
>>> vs0_le = vs0.__le__
>>> vs0_le(vs1)
VS richcmp 0 1 (kind=1)
>>> vs0_eq = vs0.__eq__
>>> vs0_eq(vs1)
VS richcmp 0 1 (kind=2)
>>> vs0_ne = vs0.__ne__
>>> vs0_ne(vs1)
VS richcmp 0 1 (kind=3)
>>> vs0_gt = vs0.__gt__
>>> vs0_gt(vs1)
VS richcmp 0 1 (kind=4)
>>> vs0_ge = vs0.__ge__
>>> vs0_ge(vs1)
VS richcmp 0 1 (kind=5)
>>> vs0_iter = vs0.__iter__
>>> vs0_iter()
VS __iter__ 0
>>> vs0_next = vs0.__next__
>>> vs0_next()
VS next/__next__ 0
>>> vs0_get = vs0.__get__
>>> vs0_get('instance', 'owner')
VS __get__ 0 'instance' 'owner'
>>> vs0_init = vs0.__init__
>>> vs0_init(0)
VS __init__ 0
"""
def __init__(self, v):
VerySpecial.__init__(self, v)
def __add__(self, other):
return VerySpecial.__add__(self, other)
def __sub__(self, other):
return VerySpecial.__sub__(self, other)
def __mul__(self, other):
return VerySpecial.__mul__(self, other)
def __div__(self, other):
return VerySpecial.__div__(self, other)
def __mod__(self, other):
return VerySpecial.__mod__(self, other)
def __divmod__(self, other):
return VerySpecial.__divmod__(self, other)
def __pow__(self, other, mod):
return VerySpecial.__pow__(self, other, mod)
def __lshift__(self, other):
return VerySpecial.__lshift__(self, other)
def __rshift__(self, other):
return VerySpecial.__rshift__(self, other)
def __and__(self, other):
return VerySpecial.__and__(self, other)
def __xor__(self, other):
return VerySpecial.__xor__(self, other)
def __or__(self, other):
return VerySpecial.__or__(self, other)
def __floordiv__(self, other):
return VerySpecial.__floordiv__(self, other)
def __truediv__(self, other):
return VerySpecial.__truediv__(self, other)
def __neg__(self):
return VerySpecial.__neg__(self)
def __pos__(self):
return VerySpecial.__pos__(self)
def __abs__(self):
return VerySpecial.__abs__(self)
def __nonzero__(self):
return VerySpecial.__nonzero__(self)
def __invert__(self):
return VerySpecial.__invert__(self)
def __int__(self):
return VerySpecial.__int__(self)
def __long__(self):
return VerySpecial.__long__(self)
def __float__(self):
return VerySpecial.__float__(self)
def __oct__(self):
return VerySpecial.__oct__(self)
def __hex__(self):
return VerySpecial.__hex__(self)
def __iadd__(self, other):
return VerySpecial.__iadd__(self, other)
def __isub__(self, other):
return VerySpecial.__isub__(self, other)
def __imul__(self, other):
return VerySpecial.__imul__(self, other)
def __idiv__(self, other):
return VerySpecial.__idiv__(self, other)
def __imod__(self, other):
return VerySpecial.__imod__(self, other)
def __ipow__(self, other):
return VerySpecial.__ipow__(self, other)
def __ilshift__(self, other):
return VerySpecial.__ilshift__(self, other)
def __irshift__(self, other):
return VerySpecial.__irshift__(self, other)
def __iand__(self, other):
return VerySpecial.__iand__(self, other)
def __ixor__(self, other):
return VerySpecial.__ixor__(self, other)
def __ior__(self, other):
return VerySpecial.__ior__(self, other)
def __ifloordiv__(self, other):
return VerySpecial.__ifloordiv__(self, other)
def __itruediv__(self, other):
return VerySpecial.__itruediv__(self, other)
def __index__(self):
return VerySpecial.__index__(self)
def __getitem__(self, index):
return VerySpecial.__getitem__(self, index)
def __contains__(self, other):
return VerySpecial.__contains__(self, other)
def __len__(self):
return VerySpecial.__len__(self)
def __cmp__(self, other):
return VerySpecial.__cmp__(self, other)
def __repr__(self):
return VerySpecial.__repr__(self)
def __hash__(self):
return VerySpecial.__hash__(self)
def __call__(self, arg):
return VerySpecial.__call__(self, arg)
def __str__(self):
return VerySpecial.__str__(self)
# there is no __richcmp__ at the Python level
# def __richcmp__(self, other, kind):
# return VerySpecial.__richcmp__(self, other, kind)
def __iter__(self):
return VerySpecial.__iter__(self)
def __next__(self):
return VerySpecial.__next__(self)
def __get__(self, inst, own):
return VerySpecial.__get__(self, inst, own)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment