Commit 628ffd74 authored by Stefan Behnel's avatar Stefan Behnel

Fix the first argument special method signatures of "__eq__", "__lt__" and the...

Fix the first argument special method signatures of "__eq__", "__lt__" and the other richcmp methods to be of "self" type, in accordance with to the CPython specs.
See https://docs.python.org/3/reference/datamodel.html#emulating-container-types
Closes #1935.
parent 4c461c93
......@@ -576,7 +576,7 @@ def get_special_method_signature(name):
if slot:
return slot.signature
elif name in richcmp_special_methods:
return binaryfunc
return ibinaryfunc
else:
return None
......
......@@ -209,21 +209,21 @@ Rich comparison operators
https://docs.python.org/3/reference/datamodel.html#basic-customization
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __richcmp__ |x, y, int op | object | Rich comparison (no direct Python equivalent) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __eq__ |x, y | object | x == y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __ne__ |x, y | object | x != y (falls back to ``__eq__`` if not available) |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __lt__ |x, y | object | x < y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __gt__ |x, y | object | x > y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __le__ |x, y | object | x <= y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
| __ge__ |x, y | object | x >= y |
+-----------------------+---------------------------------------+-------------+-----------------------------------------------------+
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __richcmp__ |x, y, int op | object | Rich comparison (no direct Python equivalent) |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __eq__ |self, y | object | self == y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __ne__ |self, y | object | self != y (falls back to ``__eq__`` if not available) |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __lt__ |self, y | object | self < y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __gt__ |self, y | object | self > y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __le__ |self, y | object | self <= y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
| __ge__ |self, y | object | self >= y |
+-----------------------+---------------------------------------+-------------+--------------------------------------------------------+
Arithmetic operators
^^^^^^^^^^^^^^^^^^^^
......
......@@ -9,7 +9,7 @@ IS_PY2 = sys.version_info[0] == 2
@cython.cclass
class X(object):
x = cython.declare(cython.int, visibility="public")
x = cython.declare(cython.int)
def __init__(self, x):
self.x = x
......@@ -18,6 +18,12 @@ class X(object):
return "<%d>" % self.x
@cython.cfunc
@cython.locals(x=X)
def x_of(x):
return x.x
@cython.cclass
class ClassEq(X):
"""
......@@ -74,9 +80,12 @@ class ClassEq(X):
TypeError...
"""
def __eq__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x == other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassEq), type(self)
if isinstance(other, X):
return self.x == x_of(other)
elif isinstance(other, int):
return self.x < other
return NotImplemented
......@@ -134,9 +143,12 @@ class ClassEqNe(ClassEq):
TypeError...
"""
def __ne__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x != other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassEqNe), type(self)
if isinstance(other, X):
return self.x != x_of(other)
elif isinstance(other, int):
return self.x < other
return NotImplemented
......@@ -208,11 +220,34 @@ class ClassEqNeGe(ClassEqNe):
... else: a > b
Traceback (most recent call last):
TypeError...
"""
>>> 2 <= a
False
>>> a >= 2
False
>>> 1 <= a
True
>>> a >= 1
True
>>> a >= 2
False
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 'x' <= a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: a >= 'x'
Traceback (most recent call last):
TypeError...
"""
def __ge__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x >= other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassEqNeGe), type(self)
if isinstance(other, X):
return self.x >= x_of(other)
elif isinstance(other, int):
return self.x >= other
return NotImplemented
......@@ -274,11 +309,34 @@ class ClassLe(X):
True
>>> b >= c
True
>>> 2 >= a
True
>>> a <= 2
True
>>> 1 >= a
True
>>> a <= 1
True
>>> a <= 0
False
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 'x' >= a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: a <= 'x'
Traceback (most recent call last):
TypeError...
"""
def __le__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x <= other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassLe), type(self)
if isinstance(other, X):
return self.x <= x_of(other)
elif isinstance(other, int):
return self.x <= other
return NotImplemented
......@@ -320,11 +378,37 @@ class ClassLt(X):
[<1>, <1>, <2>]
>>> sorted([b, a, c])
[<1>, <1>, <2>]
>>> 2 > a
True
>>> a < 2
True
>>> 1 > a
False
>>> a < 1
False
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 1 < a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 'x' > a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: a < 'x'
Traceback (most recent call last):
TypeError...
"""
def __lt__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x < other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassLt), type(self)
if isinstance(other, X):
return self.x < x_of(other)
elif isinstance(other, int):
return self.x < other
return NotImplemented
......@@ -368,9 +452,12 @@ class ClassLtGtInherited(X):
[<1>, <1>, <2>]
"""
def __gt__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x > other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassLtGtInherited), type(self)
if isinstance(other, X):
return self.x > x_of(other)
elif isinstance(other, int):
return self.x > other
return NotImplemented
......@@ -412,17 +499,49 @@ class ClassLtGt(X):
[<1>, <1>, <2>]
>>> sorted([b, a, c])
[<1>, <1>, <2>]
>>> 2 > a
True
>>> 2 < a
False
>>> a < 2
True
>>> a > 2
False
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 'x' > a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: 'x' < a
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: a < 'x'
Traceback (most recent call last):
TypeError...
>>> if IS_PY2: raise TypeError # doctest: +ELLIPSIS
... else: a > 'x'
Traceback (most recent call last):
TypeError...
"""
def __lt__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x < other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassLtGt), type(self)
if isinstance(other, X):
return self.x < x_of(other)
elif isinstance(other, int):
return self.x < other
return NotImplemented
def __gt__(self, other):
if isinstance(self, X):
if isinstance(other, X):
return self.x > other.x
assert 1 <= self.x <= 2
assert isinstance(self, ClassLtGt), type(self)
if isinstance(other, X):
return self.x > x_of(other)
elif isinstance(other, int):
return self.x > other
return NotImplemented
......
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