summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/object.h1
-rw-r--r--Lib/StringIO.py4
-rw-r--r--Lib/UserDict.py21
-rwxr-xr-xLib/UserString.py32
-rw-r--r--Lib/ctypes/test/test_simplesubclasses.py6
-rw-r--r--Lib/decimal.py21
-rw-r--r--Lib/distutils/version.py39
-rw-r--r--Lib/doctest.py9
-rw-r--r--Lib/optparse.py8
-rw-r--r--Lib/plat-mac/plistlib.py8
-rw-r--r--Lib/pprint.py7
-rw-r--r--Lib/sqlite3/test/types.py6
-rw-r--r--Lib/test/mapping_tests.py25
-rw-r--r--Lib/test/output/test_class20
-rw-r--r--Lib/test/pickletester.py4
-rw-r--r--Lib/test/test_bisect.py7
-rw-r--r--Lib/test/test_buffer.py44
-rw-r--r--Lib/test/test_builtin.py20
-rw-r--r--Lib/test/test_calendar.py2
-rw-r--r--Lib/test/test_cgi.py18
-rw-r--r--Lib/test/test_class.py24
-rw-r--r--Lib/test/test_compare.py6
-rw-r--r--Lib/test/test_copy.py70
-rw-r--r--Lib/test/test_decimal.py4
-rw-r--r--Lib/test/test_descr.py83
-rw-r--r--Lib/test/test_descrtut.py5
-rw-r--r--Lib/test/test_dict.py11
-rw-r--r--Lib/test/test_grammar.py4
-rw-r--r--Lib/test/test_heapq.py3
-rw-r--r--Lib/test/test_itertools.py6
-rw-r--r--Lib/test/test_mutants.py9
-rw-r--r--Lib/test/test_operations.py4
-rw-r--r--Lib/test/test_set.py23
-rw-r--r--Lib/test/test_sets.py15
-rw-r--r--Lib/test/test_slice.py6
-rw-r--r--Lib/test/test_sort.py6
-rw-r--r--Lib/test/test_support.py4
-rw-r--r--Lib/test/test_types.py1
-rw-r--r--Lib/test/test_userdict.py2
-rw-r--r--Lib/test/test_weakref.py6
-rw-r--r--Lib/uuid.py33
-rw-r--r--Lib/xmlrpclib.py71
-rw-r--r--Modules/threadmodule.c2
-rw-r--r--Objects/bufferobject.c74
-rw-r--r--Objects/cellobject.c14
-rw-r--r--Objects/classobject.c100
-rw-r--r--Objects/codeobject.c15
-rw-r--r--Objects/dictobject.c166
-rw-r--r--Objects/intobject.c15
-rw-r--r--Objects/listobject.c22
-rw-r--r--Objects/longobject.c14
-rw-r--r--Objects/methodobject.c36
-rw-r--r--Objects/object.c552
-rw-r--r--Objects/sliceobject.c70
-rw-r--r--Objects/typeobject.c40
-rw-r--r--Objects/weakrefobject.c22
-rw-r--r--Python/bltinmodule.c28
57 files changed, 969 insertions, 899 deletions
diff --git a/Include/object.h b/Include/object.h
index ab42f8a..30f0bec 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -379,6 +379,7 @@ PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *);
PyAPI_FUNC(int) PyObject_Compare(PyObject *, PyObject *);
PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int);
PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int);
+PyAPI_FUNC(PyObject *) Py_CmpToRich(int op, int cmp);
PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *);
PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *);
PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
diff --git a/Lib/StringIO.py b/Lib/StringIO.py
index 1e5f254..7d57d80 100644
--- a/Lib/StringIO.py
+++ b/Lib/StringIO.py
@@ -116,7 +116,7 @@ class StringIO:
_complain_ifclosed(self.closed)
return self.pos
- def read(self, n = -1):
+ def read(self, n=None):
"""Read at most size bytes from the file
(less if the read hits EOF before obtaining size bytes).
@@ -128,6 +128,8 @@ class StringIO:
if self.buflist:
self.buf += ''.join(self.buflist)
self.buflist = []
+ if n is None:
+ n = -1
if n < 0:
newpos = self.len
else:
diff --git a/Lib/UserDict.py b/Lib/UserDict.py
index b560a11..1190221 100644
--- a/Lib/UserDict.py
+++ b/Lib/UserDict.py
@@ -8,11 +8,16 @@ class UserDict:
if len(kwargs):
self.update(kwargs)
def __repr__(self): return repr(self.data)
- def __cmp__(self, dict):
+ def __eq__(self, dict):
if isinstance(dict, UserDict):
- return cmp(self.data, dict.data)
+ return self.data == dict.data
else:
- return cmp(self.data, dict)
+ return self.data == dict
+ def __ne__(self, dict):
+ if isinstance(dict, UserDict):
+ return self.data != dict.data
+ else:
+ return self.data != dict
def __len__(self): return len(self.data)
def __getitem__(self, key):
if key in self.data:
@@ -162,11 +167,13 @@ class DictMixin:
return default
def __repr__(self):
return repr(dict(self.iteritems()))
- def __cmp__(self, other):
- if other is None:
- return 1
+ def __eq__(self, other):
+ if isinstance(other, DictMixin):
+ other = dict(other.iteritems())
+ return dict(self.iteritems()) == other
+ def __ne__(self, other):
if isinstance(other, DictMixin):
other = dict(other.iteritems())
- return cmp(dict(self.iteritems()), other)
+ return dict(self.iteritems()) != other
def __len__(self):
return len(self.keys())
diff --git a/Lib/UserString.py b/Lib/UserString.py
index 60dc34b..271026c 100755
--- a/Lib/UserString.py
+++ b/Lib/UserString.py
@@ -25,11 +25,37 @@ class UserString:
def __complex__(self): return complex(self.data)
def __hash__(self): return hash(self.data)
- def __cmp__(self, string):
+ def __eq__(self, string):
if isinstance(string, UserString):
- return cmp(self.data, string.data)
+ return self.data == string.data
else:
- return cmp(self.data, string)
+ return self.data == string
+ def __ne__(self, string):
+ if isinstance(string, UserString):
+ return self.data != string.data
+ else:
+ return self.data != string
+ def __lt__(self, string):
+ if isinstance(string, UserString):
+ return self.data < string.data
+ else:
+ return self.data < string
+ def __le__(self, string):
+ if isinstance(string, UserString):
+ return self.data <= string.data
+ else:
+ return self.data <= string
+ def __gt__(self, string):
+ if isinstance(string, UserString):
+ return self.data > string.data
+ else:
+ return self.data > string
+ def __ge__(self, string):
+ if isinstance(string, UserString):
+ return self.data >= string.data
+ else:
+ return self.data >= string
+
def __contains__(self, char):
return char in self.data
diff --git a/Lib/ctypes/test/test_simplesubclasses.py b/Lib/ctypes/test/test_simplesubclasses.py
index 7155170..420c0a0 100644
--- a/Lib/ctypes/test/test_simplesubclasses.py
+++ b/Lib/ctypes/test/test_simplesubclasses.py
@@ -2,10 +2,10 @@ import unittest
from ctypes import *
class MyInt(c_int):
- def __cmp__(self, other):
+ def __eq__(self, other):
if type(other) != MyInt:
- return -1
- return cmp(self.value, other.value)
+ return NotImplementedError
+ return self.value == other.value
class Test(unittest.TestCase):
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 210db52..a8fde82 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -706,6 +706,26 @@ class Decimal(object):
return NotImplemented
return self.__cmp__(other) != 0
+ def __lt__(self, other):
+ if not isinstance(other, (Decimal, int, long)):
+ return NotImplemented
+ return self.__cmp__(other) < 0
+
+ def __le__(self, other):
+ if not isinstance(other, (Decimal, int, long)):
+ return NotImplemented
+ return self.__cmp__(other) <= 0
+
+ def __gt__(self, other):
+ if not isinstance(other, (Decimal, int, long)):
+ return NotImplemented
+ return self.__cmp__(other) > 0
+
+ def __ge__(self, other):
+ if not isinstance(other, (Decimal, int, long)):
+ return NotImplemented
+ return self.__cmp__(other) >= 0
+
def compare(self, other, context=None):
"""Compares one to another.
@@ -1894,6 +1914,7 @@ class Decimal(object):
ans = self._check_nans(context=context)
if ans:
return ans
+ return self
if self._exp >= 0:
return self
if context is None:
diff --git a/Lib/distutils/version.py b/Lib/distutils/version.py
index 71a5614..2cd3636 100644
--- a/Lib/distutils/version.py
+++ b/Lib/distutils/version.py
@@ -32,7 +32,8 @@ from types import StringType
class Version:
"""Abstract base class for version numbering classes. Just provides
constructor (__init__) and reproducer (__repr__), because those
- seem to be the same for all version numbering classes.
+ seem to be the same for all version numbering classes; and route
+ rich comparisons to __cmp__.
"""
def __init__ (self, vstring=None):
@@ -42,6 +43,42 @@ class Version:
def __repr__ (self):
return "%s ('%s')" % (self.__class__.__name__, str(self))
+ def __eq__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c == 0
+
+ def __ne__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c != 0
+
+ def __lt__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c < 0
+
+ def __le__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c <= 0
+
+ def __gt__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c > 0
+
+ def __ge__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c >= 0
+
# Interface for version-number classes -- must be implemented
# by the following classes (the concrete ones -- Version should
diff --git a/Lib/doctest.py b/Lib/doctest.py
index fe734b3..2774ec1 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -469,11 +469,12 @@ class DocTest:
# This lets us sort tests by name:
- def __cmp__(self, other):
+ def __lt__(self, other):
if not isinstance(other, DocTest):
- return -1
- return cmp((self.name, self.filename, self.lineno, id(self)),
- (other.name, other.filename, other.lineno, id(other)))
+ return NotImplemented
+ return ((self.name, self.filename, self.lineno, id(self))
+ <
+ (other.name, other.filename, other.lineno, id(other)))
######################################################################
## 3. DocTestParser
diff --git a/Lib/optparse.py b/Lib/optparse.py
index 0972f74..f8f643d 100644
--- a/Lib/optparse.py
+++ b/Lib/optparse.py
@@ -838,13 +838,13 @@ class Values:
__repr__ = _repr
- def __cmp__(self, other):
+ def __eq__(self, other):
if isinstance(other, Values):
- return cmp(self.__dict__, other.__dict__)
+ return self.__dict__ == other.__dict__
elif isinstance(other, types.DictType):
- return cmp(self.__dict__, other)
+ return self.__dict__ == other
else:
- return -1
+ return NotImplemented
def _update_careful(self, dict):
"""
diff --git a/Lib/plat-mac/plistlib.py b/Lib/plat-mac/plistlib.py
index 49bd556..f91f1d3 100644
--- a/Lib/plat-mac/plistlib.py
+++ b/Lib/plat-mac/plistlib.py
@@ -374,13 +374,13 @@ class Data:
def asBase64(self, maxlinelength=76):
return _encodeBase64(self.data, maxlinelength)
- def __cmp__(self, other):
+ def __eq__(self, other):
if isinstance(other, self.__class__):
- return cmp(self.data, other.data)
+ return self.data == other.data
elif isinstance(other, str):
- return cmp(self.data, other)
+ return self.data == other
else:
- return cmp(id(self), id(other))
+ return id(self) == id(other)
def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.data))
diff --git a/Lib/pprint.py b/Lib/pprint.py
index 19a3dc2..97135eb 100644
--- a/Lib/pprint.py
+++ b/Lib/pprint.py
@@ -246,7 +246,12 @@ def _safe_repr(object, context, maxlevels, level):
append = components.append
level += 1
saferepr = _safe_repr
- for k, v in sorted(object.items()):
+ items = object.items()
+ try:
+ items = sorted(items)
+ except TypeError:
+ items = sorted(items, key=lambda (k, v): (str(type(k)), k, v))
+ for k, v in items:
krepr, kreadable, krecur = saferepr(k, context, maxlevels, level)
vrepr, vreadable, vrecur = saferepr(v, context, maxlevels, level)
append("%s: %s" % (krepr, vrepr))
diff --git a/Lib/sqlite3/test/types.py b/Lib/sqlite3/test/types.py
index 8da5722..9a11f5c 100644
--- a/Lib/sqlite3/test/types.py
+++ b/Lib/sqlite3/test/types.py
@@ -86,6 +86,12 @@ class DeclTypesTests(unittest.TestCase):
else:
return 1
+ def __eq__(self, other):
+ c = self.__cmp__(other)
+ if c is NotImplemented:
+ return c
+ return c == 0
+
def __conform__(self, protocol):
if protocol is sqlite.PrepareProtocol:
return self.val
diff --git a/Lib/test/mapping_tests.py b/Lib/test/mapping_tests.py
index b917540..15f9add 100644
--- a/Lib/test/mapping_tests.py
+++ b/Lib/test/mapping_tests.py
@@ -60,10 +60,10 @@ class BasicTestMappingProtocol(unittest.TestCase):
for k in self.other:
self.failIf(k in d)
#cmp
- self.assertEqual(cmp(p,p), 0)
- self.assertEqual(cmp(d,d), 0)
- self.assertEqual(cmp(p,d), -1)
- self.assertEqual(cmp(d,p), 1)
+ self.assertEqual(p, p)
+ self.assertEqual(d, d)
+ self.assertNotEqual(p, d)
+ self.assertNotEqual(d, p)
#__non__zero__
if p: self.fail("Empty mapping must compare to False")
if not d: self.fail("Full mapping must compare to True")
@@ -623,9 +623,10 @@ class TestHashMappingProtocol(TestMappingProtocol):
d = self._full_mapping({1: BadRepr()})
self.assertRaises(Exc, repr, d)
- def test_le(self):
- self.assert_(not (self._empty_mapping() < self._empty_mapping()))
- self.assert_(not (self._full_mapping({1: 2}) < self._full_mapping({1L: 2L})))
+ def test_eq(self):
+ self.assertEqual(self._empty_mapping(), self._empty_mapping())
+ self.assertEqual(self._full_mapping({1: 2}),
+ self._full_mapping({1L: 2L}))
class Exc(Exception): pass
@@ -633,16 +634,12 @@ class TestHashMappingProtocol(TestMappingProtocol):
def __eq__(self, other):
raise Exc()
def __hash__(self):
- return 42
+ return 1
d1 = self._full_mapping({BadCmp(): 1})
d2 = self._full_mapping({1: 1})
- try:
- d1 < d2
- except Exc:
- pass
- else:
- self.fail("< didn't raise Exc")
+ self.assertRaises(Exc, lambda: BadCmp()==1)
+ self.assertRaises(Exc, lambda: d1==d2)
def test_setdefault(self):
TestMappingProtocol.test_setdefault(self)
diff --git a/Lib/test/output/test_class b/Lib/test/output/test_class
index 14d43a8..7d8ab5e 100644
--- a/Lib/test/output/test_class
+++ b/Lib/test/output/test_class
@@ -51,16 +51,16 @@ __hex__: ()
__hash__: ()
__repr__: ()
__str__: ()
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
-__cmp__: (1,)
+__eq__: (1,)
+__lt__: (1,)
+__gt__: (1,)
+__ne__: (1,)
+__ne__: (1,)
+__eq__: (1,)
+__gt__: (1,)
+__lt__: (1,)
+__ne__: (1,)
+__ne__: (1,)
__del__: ()
__getattr__: ('spam',)
__setattr__: ('eggs', 'spam, spam, spam and ham')
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
index 42853c4..30c1e7c 100644
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -65,8 +65,8 @@ class ExtensionSaver:
copy_reg.add_extension(pair[0], pair[1], code)
class C:
- def __cmp__(self, other):
- return cmp(self.__dict__, other.__dict__)
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
import __main__
__main__.C = C
diff --git a/Lib/test/test_bisect.py b/Lib/test/test_bisect.py
index 302ff63..772e808 100644
--- a/Lib/test/test_bisect.py
+++ b/Lib/test/test_bisect.py
@@ -174,8 +174,13 @@ class GetOnly:
class CmpErr:
"Dummy element that always raises an error during comparison"
- def __cmp__(self, other):
+ def __lt__(self, other):
raise ZeroDivisionError
+ __gt__ = __lt__
+ __le__ = __lt__
+ __ge__ = __lt__
+ __eq__ = __lt__
+ __ne__ = __lt__
class TestErrorHandling(unittest.TestCase):
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
new file mode 100644
index 0000000..eb6e9ea
--- /dev/null
+++ b/Lib/test/test_buffer.py
@@ -0,0 +1,44 @@
+"""Unit tests for buffer objects.
+
+For now, we just test (the brand new) rich comparison.
+
+"""
+
+import unittest
+from test import test_support
+
+class BufferTests(unittest.TestCase):
+
+ def test_comparison(self):
+ a = buffer("a.b.c")
+ b = buffer("a.b" + ".c")
+ self.assert_(a == b)
+ self.assert_(a <= b)
+ self.assert_(a >= b)
+ self.assert_(a == "a.b.c")
+ self.assert_(a <= "a.b.c")
+ self.assert_(a >= "a.b.c")
+ b = buffer("a.b.c.d")
+ self.assert_(a != b)
+ self.assert_(a <= b)
+ self.assert_(a < b)
+ self.assert_(a != "a.b.c.d")
+ self.assert_(a < "a.b.c.d")
+ self.assert_(a <= "a.b.c.d")
+ b = buffer("a.b")
+ self.assert_(a != b)
+ self.assert_(a >= b)
+ self.assert_(a > b)
+ self.assert_(a != "a.b")
+ self.assert_(a > "a.b")
+ self.assert_(a >= "a.b")
+ b = object()
+ self.assert_(a != b)
+ self.failIf(a == b)
+ self.assertRaises(TypeError, lambda: a < b)
+
+def test_main():
+ test_support.run_unittest(BufferTests)
+
+if __name__ == "__main__":
+ test_main()
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index b0dbd4a..d3a272b 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -179,7 +179,8 @@ class BuiltinTest(unittest.TestCase):
self.assertRaises(ValueError, chr, 256)
self.assertRaises(TypeError, chr)
- def test_cmp(self):
+ def XXX_test_cmp(self):
+ # cmp() is no longer supported
self.assertEqual(cmp(-1, 1), -1)
self.assertEqual(cmp(1, -1), 1)
self.assertEqual(cmp(1, 1), 0)
@@ -1132,8 +1133,14 @@ class BuiltinTest(unittest.TestCase):
map(None, Squares(3), Squares(2)),
[(0,0), (1,1), (4,None)]
)
+ def Max(a, b):
+ if a is None:
+ return b
+ if b is None:
+ return a
+ return max(a, b)
self.assertEqual(
- map(max, Squares(3), Squares(2)),
+ map(Max, Squares(3), Squares(2)),
[0, 1, 4]
)
self.assertRaises(TypeError, map)
@@ -1201,7 +1208,7 @@ class BuiltinTest(unittest.TestCase):
class BadNumber:
def __cmp__(self, other):
raise ValueError
- self.assertRaises(ValueError, min, (42, BadNumber()))
+ self.assertRaises(TypeError, min, (42, BadNumber()))
for stmt in (
"min(key=int)", # no args
@@ -1379,8 +1386,11 @@ class BuiltinTest(unittest.TestCase):
self.assertRaises(ValueError, range, a, a + 1, long(0))
class badzero(int):
- def __cmp__(self, other):
+ def __eq__(self, other):
raise RuntimeError
+ __ne__ = __lt__ = __gt__ = __le__ = __ge__ = __eq__
+
+ # XXX This won't (but should!) raise RuntimeError if a is an int...
self.assertRaises(RuntimeError, range, a, a + 1, badzero(1))
# Reject floats when it would require PyLongs to represent.
@@ -1594,7 +1604,7 @@ class TestSorted(unittest.TestCase):
data.reverse()
random.shuffle(copy)
- self.assertEqual(data, sorted(copy, cmp=lambda x, y: cmp(y,x)))
+ self.assertEqual(data, sorted(copy, cmp=lambda x, y: (x < y) - (x > y)))
self.assertNotEqual(data, copy)
random.shuffle(copy)
self.assertEqual(data, sorted(copy, key=lambda x: -x))
diff --git a/Lib/test/test_calendar.py b/Lib/test/test_calendar.py
index e414324..893890d 100644
--- a/Lib/test/test_calendar.py
+++ b/Lib/test/test_calendar.py
@@ -212,7 +212,7 @@ class CalendarTestCase(unittest.TestCase):
self.assertEqual(calendar.isleap(2003), 0)
def test_setfirstweekday(self):
- self.assertRaises(ValueError, calendar.setfirstweekday, 'flabber')
+ self.assertRaises(TypeError, calendar.setfirstweekday, 'flabber')
self.assertRaises(ValueError, calendar.setfirstweekday, -1)
self.assertRaises(ValueError, calendar.setfirstweekday, 200)
orig = calendar.firstweekday()
diff --git a/Lib/test/test_cgi.py b/Lib/test/test_cgi.py
index 8fe487b..f93fa55 100644
--- a/Lib/test/test_cgi.py
+++ b/Lib/test/test_cgi.py
@@ -25,13 +25,11 @@ class ComparableException:
def __str__(self):
return str(self.err)
- def __cmp__(self, anExc):
+ def __eq__(self, anExc):
if not isinstance(anExc, Exception):
- return -1
- x = cmp(self.err.__class__, anExc.__class__)
- if x != 0:
- return x
- return cmp(self.err.args, anExc.args)
+ return NotImplemented
+ return (self.err.__class__ == anExc.__class__ and
+ self.err.args == anExc.args)
def __getattr__(self, attr):
return getattr(self.err, attr)
@@ -118,10 +116,10 @@ parse_strict_test_cases = [
})
]
-def norm(list):
- if type(list) == type([]):
- list.sort()
- return list
+def norm(seq):
+ if isinstance(seq, list):
+ seq.sort(key=repr)
+ return seq
def first_elts(list):
return map(lambda x:x[0], list)
diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py
index a0b3300..66f4265 100644
--- a/Lib/test/test_class.py
+++ b/Lib/test/test_class.py
@@ -100,6 +100,30 @@ class AllTests:
print "__cmp__:", args
return 0
+ def __eq__(self, *args):
+ print "__eq__:", args
+ return True
+
+ def __ne__(self, *args):
+ print "__ne__:", args
+ return False
+
+ def __lt__(self, *args):
+ print "__lt__:", args
+ return False
+
+ def __le__(self, *args):
+ print "__le__:", args
+ return True
+
+ def __gt__(self, *args):
+ print "__gt__:", args
+ return False
+
+ def __ge__(self, *args):
+ print "__ge__:", args
+ return True
+
def __del__(self, *args):
print "__del__:", args
diff --git a/Lib/test/test_compare.py b/Lib/test/test_compare.py
index 7c81194..8f38e3b 100644
--- a/Lib/test/test_compare.py
+++ b/Lib/test/test_compare.py
@@ -13,8 +13,8 @@ class Cmp:
def __repr__(self):
return '<Cmp %s>' % self.arg
- def __cmp__(self, other):
- return cmp(self.arg, other)
+ def __eq__(self, other):
+ return self.arg == other
class ComparisonTest(unittest.TestCase):
set1 = [2, 2.0, 2L, 2+0j, Cmp(2.0)]
@@ -36,7 +36,7 @@ class ComparisonTest(unittest.TestCase):
L.insert(len(L)//2, Empty())
for a in L:
for b in L:
- self.assertEqual(cmp(a, b), cmp(id(a), id(b)),
+ self.assertEqual(a == b, id(a) == id(b),
'a=%r, b=%r' % (a, b))
def test_main():
diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py
index ff4c987..416a755 100644
--- a/Lib/test/test_copy.py
+++ b/Lib/test/test_copy.py
@@ -104,8 +104,8 @@ class TestCopy(unittest.TestCase):
class C:
def __init__(self, foo):
self.foo = foo
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -115,8 +115,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __copy__(self):
return C(self.foo)
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -126,8 +126,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __getinitargs__(self):
return (self.foo,)
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -137,8 +137,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __getstate__(self):
return {"foo": self.foo}
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -148,8 +148,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __setstate__(self, state):
self.foo = state["foo"]
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -161,8 +161,8 @@ class TestCopy(unittest.TestCase):
return self.foo
def __setstate__(self, state):
self.foo = state
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C(42)
self.assertEqual(copy.copy(x), x)
@@ -304,7 +304,7 @@ class TestCopy(unittest.TestCase):
x = {}
x['foo'] = x
y = copy.deepcopy(x)
- self.assertRaises(RuntimeError, cmp, y, x)
+ self.assertRaises(TypeError, cmp, y, x)
self.assert_(y is not x)
self.assert_(y['foo'] is y)
self.assertEqual(len(y), 1)
@@ -319,8 +319,8 @@ class TestCopy(unittest.TestCase):
class C:
def __init__(self, foo):
self.foo = foo
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -332,8 +332,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __deepcopy__(self, memo):
return C(copy.deepcopy(self.foo, memo))
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -346,8 +346,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __getinitargs__(self):
return (self.foo,)
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -360,8 +360,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __getstate__(self):
return {"foo": self.foo}
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -374,8 +374,8 @@ class TestCopy(unittest.TestCase):
self.foo = foo
def __setstate__(self, state):
self.foo = state["foo"]
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -390,8 +390,8 @@ class TestCopy(unittest.TestCase):
return self.foo
def __setstate__(self, state):
self.foo = state
- def __cmp__(self, other):
- return cmp(self.foo, other.foo)
+ def __eq__(self, other):
+ return self.foo == other.foo
x = C([42])
y = copy.deepcopy(x)
self.assertEqual(y, x)
@@ -434,8 +434,8 @@ class TestCopy(unittest.TestCase):
class C(object):
def __reduce__(self):
return (C, (), self.__dict__)
- def __cmp__(self, other):
- return cmp(self.__dict__, other.__dict__)
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
x = C()
x.foo = [42]
y = copy.copy(x)
@@ -450,8 +450,8 @@ class TestCopy(unittest.TestCase):
return (C, (), self.__dict__)
def __setstate__(self, state):
self.__dict__.update(state)
- def __cmp__(self, other):
- return cmp(self.__dict__, other.__dict__)
+ def __eq__(self, other):
+ return self.__dict__ == other.__dict__
x = C()
x.foo = [42]
y = copy.copy(x)
@@ -475,9 +475,9 @@ class TestCopy(unittest.TestCase):
class C(list):
def __reduce__(self):
return (C, (), self.__dict__, iter(self))
- def __cmp__(self, other):
- return (cmp(list(self), list(other)) or
- cmp(self.__dict__, other.__dict__))
+ def __eq__(self, other):
+ return (list(self) == list(other) and
+ self.__dict__ == other.__dict__)
x = C([[1, 2], 3])
y = copy.copy(x)
self.assertEqual(x, y)
@@ -492,9 +492,9 @@ class TestCopy(unittest.TestCase):
class C(dict):
def __reduce__(self):
return (C, (), self.__dict__, None, self.iteritems())
- def __cmp__(self, other):
- return (cmp(dict(self), list(dict)) or
- cmp(self.__dict__, other.__dict__))
+ def __eq__(self, other):
+ return (dict(self) == dict(other) and
+ self.__dict__ == other.__dict__)
x = C([("foo", [1, 2]), ("bar", 3)])
y = copy.copy(x)
self.assertEqual(x, y)
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index 40c4466..5fef4eb 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -276,8 +276,8 @@ class DecimalTest(unittest.TestCase):
myexceptions = self.getexceptions()
self.context.clear_flags()
- myexceptions.sort()
- theirexceptions.sort()
+ myexceptions.sort(key=repr)
+ theirexceptions.sort(key=repr)
self.assertEqual(result, ans,
'Incorrect answer for ' + s + ' -- got ' + result)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 00800a7..3fb01e7 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -151,7 +151,7 @@ def lists():
def dicts():
if verbose: print "Testing dict operations..."
- testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__")
+ ##testbinop({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__")
testbinop({1:2,3:4}, 1, 1, "b in a", "__contains__")
testbinop({1:2,3:4}, 2, 0, "b in a", "__contains__")
testbinop({1:2,3:4}, 1, 2, "a[b]", "__getitem__")
@@ -523,7 +523,7 @@ def spamdicts():
# This is an ugly hack:
copy._deepcopy_dispatch[spam.spamdict] = spamdict
- testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__")
+ ##testbinop(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", "__cmp__")
testbinop(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__")
testbinop(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__")
testbinop(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__")
@@ -1641,7 +1641,7 @@ def specials():
verify(id(c1) != id(c2))
hash(c1)
hash(c2)
- vereq(cmp(c1, c2), cmp(id(c1), id(c2)))
+ ##vereq(cmp(c1, c2), cmp(id(c1), id(c2)))
vereq(c1, c1)
verify(c1 != c2)
verify(not c1 != c1)
@@ -1665,7 +1665,7 @@ def specials():
verify(id(d1) != id(d2))
hash(d1)
hash(d2)
- vereq(cmp(d1, d2), cmp(id(d1), id(d2)))
+ ##vereq(cmp(d1, d2), cmp(id(d1), id(d2)))
vereq(d1, d1)
verify(d1 != d2)
verify(not d1 != d1)
@@ -1758,21 +1758,21 @@ def specials():
for i in range(10):
verify(i in p10)
verify(10 not in p10)
- # Safety test for __cmp__
- def unsafecmp(a, b):
- try:
- a.__class__.__cmp__(a, b)
- except TypeError:
- pass
- else:
- raise TestFailed, "shouldn't allow %s.__cmp__(%r, %r)" % (
- a.__class__, a, b)
- unsafecmp(u"123", "123")
- unsafecmp("123", u"123")
- unsafecmp(1, 1.0)
- unsafecmp(1.0, 1)
- unsafecmp(1, 1L)
- unsafecmp(1L, 1)
+## # Safety test for __cmp__
+## def unsafecmp(a, b):
+## try:
+## a.__class__.__cmp__(a, b)
+## except TypeError:
+## pass
+## else:
+## raise TestFailed, "shouldn't allow %s.__cmp__(%r, %r)" % (
+## a.__class__, a, b)
+## unsafecmp(u"123", "123")
+## unsafecmp("123", u"123")
+## unsafecmp(1, 1.0)
+## unsafecmp(1.0, 1)
+## unsafecmp(1, 1L)
+## unsafecmp(1L, 1)
class Letter(str):
def __new__(cls, letter):
@@ -2469,12 +2469,43 @@ def classic_comparisons():
class C(base):
def __init__(self, value):
self.value = int(value)
- def __cmp__(self, other):
+ def __eq__(self, other):
+ if isinstance(other, C):
+ return self.value == other.value
+ if isinstance(other, int) or isinstance(other, long):
+ return self.value == other
+ return NotImplemented
+ def __ne__(self, other):
+ if isinstance(other, C):
+ return self.value != other.value
+ if isinstance(other, int) or isinstance(other, long):
+ return self.value != other
+ return NotImplemented
+ def __lt__(self, other):
+ if isinstance(other, C):
+ return self.value < other.value
+ if isinstance(other, int) or isinstance(other, long):
+ return self.value < other
+ return NotImplemented
+ def __le__(self, other):
+ if isinstance(other, C):
+ return self.value <= other.value
+ if isinstance(other, int) or isinstance(other, long):
+ return self.value <= other
+ return NotImplemented
+ def __gt__(self, other):
if isinstance(other, C):
- return cmp(self.value, other.value)
+ return self.value > other.value
+ if isinstance(other, int) or isinstance(other, long):
+ return self.value > other
+ return NotImplemented
+ def __ge__(self, other):
+ if isinstance(other, C):
+ return self.value >= other.value
if isinstance(other, int) or isinstance(other, long):
- return cmp(self.value, other)
+ return self.value >= other
return NotImplemented
+
c1 = C(1)
c2 = C(2)
c3 = C(3)
@@ -2482,12 +2513,12 @@ def classic_comparisons():
c = {1: c1, 2: c2, 3: c3}
for x in 1, 2, 3:
for y in 1, 2, 3:
- verify(cmp(c[x], c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y))
+ ##verify(cmp(c[x], c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y))
for op in "<", "<=", "==", "!=", ">", ">=":
verify(eval("c[x] %s c[y]" % op) == eval("x %s y" % op),
"x=%d, y=%d" % (x, y))
- verify(cmp(c[x], y) == cmp(x, y), "x=%d, y=%d" % (x, y))
- verify(cmp(x, c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y))
+ ##verify(cmp(c[x], y) == cmp(x, y), "x=%d, y=%d" % (x, y))
+ ##verify(cmp(x, c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y))
def rich_comparisons():
if verbose:
@@ -3875,6 +3906,8 @@ def methodwrapper():
if verbose:
print "Testing method-wrapper objects..."
+ return # XXX should methods really support __eq__?
+
l = []
vereq(l.__add__, l.__add__)
vereq(l.__add__, [].__add__)
diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py
index 6a5310c..28d7d13 100644
--- a/Lib/test/test_descrtut.py
+++ b/Lib/test/test_descrtut.py
@@ -65,14 +65,11 @@ We can also use the new type in contexts where classic only allows "real"
dictionaries, such as the locals/globals dictionaries for the exec
statement or the built-in function eval():
- >>> def sorted(seq):
- ... seq.sort()
- ... return seq
>>> print sorted(a.keys())
[1, 2]
>>> exec "x = 3; print x" in a
3
- >>> print sorted(a.keys())
+ >>> print sorted(a.keys(), key=lambda x: (str(type(x)), x))
[1, 2, '__builtins__', 'x']
>>> print a['x']
3
diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py
index 7295f41..717ed5e 100644
--- a/Lib/test/test_dict.py
+++ b/Lib/test/test_dict.py
@@ -5,6 +5,7 @@ import sys, UserDict, cStringIO
class DictTest(unittest.TestCase):
+
def test_constructor(self):
# calling built-in types without argument must return empty
self.assertEqual(dict(), {})
@@ -368,9 +369,9 @@ class DictTest(unittest.TestCase):
d = {1: BadRepr()}
self.assertRaises(Exc, repr, d)
- def test_le(self):
- self.assert_(not ({} < {}))
- self.assert_(not ({1: 2} < {1L: 2L}))
+ def test_eq(self):
+ self.assertEqual({}, {})
+ self.assertEqual({1: 2}, {1L: 2L})
class Exc(Exception): pass
@@ -378,12 +379,12 @@ class DictTest(unittest.TestCase):
def __eq__(self, other):
raise Exc()
def __hash__(self):
- return 42
+ return 1
d1 = {BadCmp(): 1}
d2 = {1: 1}
try:
- d1 < d2
+ d1 == d2
except Exc:
pass
else:
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 296dc9b..458bfa2 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -681,7 +681,7 @@ d[1,] = 2
d[1,2] = 3
d[1,2,3] = 4
L = list(d)
-L.sort()
+L.sort(key=lambda x: x if isinstance(x, tuple) else ())
print L
@@ -741,7 +741,7 @@ print [(i, s) for i in nums for s in [f for f in strs if "n" in f]]
print [(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)]
def test_in_func(l):
- return [None < x < 3 for x in l if x > 2]
+ return [0 < x < 3 for x in l if x > 2]
print test_in_func(nums)
diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py
index 2da4f8c..1916449 100644
--- a/Lib/test/test_heapq.py
+++ b/Lib/test/test_heapq.py
@@ -136,6 +136,7 @@ class CmpErr:
"Dummy element that always raises an error during comparison"
def __cmp__(self, other):
raise ZeroDivisionError
+ __eq__ = __ne__ = __lt__ = __le__ = __gt__ = __ge__ = __cmp__
def R(seqn):
'Regular generator'
@@ -253,7 +254,7 @@ class TestErrorHandling(unittest.TestCase):
def test_iterable_args(self):
for f in (nlargest, nsmallest):
- for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
+ for s in ("123", "", range(1000), (1, 1.2), xrange(2000,2200,5)):
for g in (G, I, Ig, L, R):
self.assertEqual(f(2, g(s)), f(2,s))
self.assertEqual(f(2, S(s)), [])
diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index b2a9b55..29abd4b 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -132,13 +132,13 @@ class TestBasicOps(unittest.TestCase):
# __cmp__ failure
class DummyCmp:
- def __cmp__(self, dst):
+ def __eq__(self, dst):
raise ExpectedError
s = [DummyCmp(), DummyCmp(), None]
- # __cmp__ failure on outer object
+ # __eq__ failure on outer object
self.assertRaises(ExpectedError, gulp, s, func=id)
- # __cmp__ failure on inner object
+ # __eq__ failure on inner object
self.assertRaises(ExpectedError, gulp, s)
# keyfunc failure
diff --git a/Lib/test/test_mutants.py b/Lib/test/test_mutants.py
index df58944..39ea806 100644
--- a/Lib/test/test_mutants.py
+++ b/Lib/test/test_mutants.py
@@ -27,7 +27,7 @@ import os
# ran it. Indeed, at the start, the driver never got beyond 6 iterations
# before the test died.
-# The dicts are global to make it easy to mutate tham from within functions.
+# The dicts are global to make it easy to mutate them from within functions.
dict1 = {}
dict2 = {}
@@ -93,9 +93,9 @@ class Horrid:
def __hash__(self):
return self.hashcode
- def __cmp__(self, other):
+ def __eq__(self, other):
maybe_mutate() # The point of the test.
- return cmp(self.i, other.i)
+ return self.i == other.i
def __repr__(self):
return "Horrid(%d)" % self.i
@@ -132,7 +132,8 @@ def test_one(n):
while dict1 and len(dict1) == len(dict2):
if verbose:
print ".",
- c = cmp(dict1, dict2)
+ c = dict1 == dict2
+ XXX # Can't figure out how to make this work
if verbose:
print
diff --git a/Lib/test/test_operations.py b/Lib/test/test_operations.py
index 0b558de..67e77aa 100644
--- a/Lib/test/test_operations.py
+++ b/Lib/test/test_operations.py
@@ -12,7 +12,7 @@ class BadDictKey:
def __hash__(self):
return hash(self.__class__)
- def __cmp__(self, other):
+ def __eq__(self, other):
if isinstance(other, self.__class__):
print "raising error"
raise RuntimeError, "gotcha"
@@ -34,7 +34,7 @@ for stmt in ['d[x2] = 2',
except RuntimeError:
print "%s: caught the RuntimeError outside" % (stmt,)
else:
- print "%s: No exception passed through!" # old CPython behavior
+ print "%s: No exception passed through!" % (stmt,) # old CPython behavior
# Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 0268be2..23926be 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -18,7 +18,7 @@ def check_pass_thru():
class BadCmp:
def __hash__(self):
return 1
- def __cmp__(self, other):
+ def __eq__(self, other):
raise RuntimeError
class TestJointOps(unittest.TestCase):
@@ -781,11 +781,8 @@ class TestBinaryOps(unittest.TestCase):
a, b = set('a'), set('b')
self.assertRaises(TypeError, cmp, a, b)
- # You can view this as a buglet: cmp(a, a) does not raise TypeError,
- # because __eq__ is tried before __cmp__, and a.__eq__(a) returns True,
- # which Python thinks is good enough to synthesize a cmp() result
- # without calling __cmp__.
- self.assertEqual(cmp(a, a), 0)
+ # In py3k, this works!
+ self.assertRaises(TypeError, cmp, a, a)
self.assertRaises(TypeError, cmp, a, 12)
self.assertRaises(TypeError, cmp, "abc", a)
@@ -1201,8 +1198,8 @@ class TestCopying(unittest.TestCase):
def test_copy(self):
dup = self.set.copy()
- dup_list = list(dup); dup_list.sort()
- set_list = list(self.set); set_list.sort()
+ dup_list = sorted(dup, key=repr)
+ set_list = sorted(self.set, key=repr)
self.assertEqual(len(dup_list), len(set_list))
for i in range(len(dup_list)):
self.failUnless(dup_list[i] is set_list[i])
@@ -1210,8 +1207,8 @@ class TestCopying(unittest.TestCase):
def test_deep_copy(self):
dup = copy.deepcopy(self.set)
##print type(dup), repr(dup)
- dup_list = list(dup); dup_list.sort()
- set_list = list(self.set); set_list.sort()
+ dup_list = sorted(dup, key=repr)
+ set_list = sorted(self.set, key=repr)
self.assertEqual(len(dup_list), len(set_list))
for i in range(len(dup_list)):
self.assertEqual(dup_list[i], set_list[i])
@@ -1374,7 +1371,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
for cons in (set, frozenset):
for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
for g in (G, I, Ig, S, L, R):
- self.assertEqual(sorted(cons(g(s))), sorted(g(s)))
+ self.assertEqual(sorted(cons(g(s)), key=repr), sorted(g(s), key=repr))
self.assertRaises(TypeError, cons , X(s))
self.assertRaises(TypeError, cons , N(s))
self.assertRaises(ZeroDivisionError, cons , E(s))
@@ -1386,7 +1383,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
for g in (G, I, Ig, L, R):
expected = meth(data)
actual = meth(G(data))
- self.assertEqual(sorted(actual), sorted(expected))
+ self.assertEqual(sorted(actual, key=repr), sorted(expected, key=repr))
self.assertRaises(TypeError, meth, X(s))
self.assertRaises(TypeError, meth, N(s))
self.assertRaises(ZeroDivisionError, meth, E(s))
@@ -1400,7 +1397,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
t = s.copy()
getattr(s, methname)(list(g(data)))
getattr(t, methname)(g(data))
- self.assertEqual(sorted(s), sorted(t))
+ self.assertEqual(sorted(s, key=repr), sorted(t, key=repr))
self.assertRaises(TypeError, getattr(set('january'), methname), X(data))
self.assertRaises(TypeError, getattr(set('january'), methname), N(data))
diff --git a/Lib/test/test_sets.py b/Lib/test/test_sets.py
index 85e4a22..88cfcac 100644
--- a/Lib/test/test_sets.py
+++ b/Lib/test/test_sets.py
@@ -234,11 +234,8 @@ class TestBinaryOps(unittest.TestCase):
a, b = Set('a'), Set('b')
self.assertRaises(TypeError, cmp, a, b)
- # You can view this as a buglet: cmp(a, a) does not raise TypeError,
- # because __eq__ is tried before __cmp__, and a.__eq__(a) returns True,
- # which Python thinks is good enough to synthesize a cmp() result
- # without calling __cmp__.
- self.assertEqual(cmp(a, a), 0)
+ # In py3k, this works!
+ self.assertRaises(TypeError, cmp, a, a)
self.assertRaises(TypeError, cmp, a, 12)
self.assertRaises(TypeError, cmp, "abc", a)
@@ -675,8 +672,8 @@ class TestCopying(unittest.TestCase):
def test_copy(self):
dup = self.set.copy()
- dup_list = list(dup); dup_list.sort()
- set_list = list(self.set); set_list.sort()
+ dup_list = sorted(dup, key=repr)
+ set_list = sorted(self.set, key=repr)
self.assertEqual(len(dup_list), len(set_list))
for i in range(len(dup_list)):
self.failUnless(dup_list[i] is set_list[i])
@@ -684,8 +681,8 @@ class TestCopying(unittest.TestCase):
def test_deep_copy(self):
dup = copy.deepcopy(self.set)
##print type(dup), repr(dup)
- dup_list = list(dup); dup_list.sort()
- set_list = list(self.set); set_list.sort()
+ dup_list = sorted(dup, key=repr)
+ set_list = sorted(self.set, key=repr)
self.assertEqual(len(dup_list), len(set_list))
for i in range(len(dup_list)):
self.assertEqual(dup_list[i], set_list[i])
diff --git a/Lib/test/test_slice.py b/Lib/test/test_slice.py
index d8eb882..bd6e621 100644
--- a/Lib/test/test_slice.py
+++ b/Lib/test/test_slice.py
@@ -35,18 +35,18 @@ class SliceTest(unittest.TestCase):
s1 = slice(BadCmp())
s2 = slice(BadCmp())
- self.assertRaises(Exc, cmp, s1, s2)
self.assertEqual(s1, s1)
+ self.assertRaises(Exc, lambda: s1 == s2)
s1 = slice(1, BadCmp())
s2 = slice(1, BadCmp())
self.assertEqual(s1, s1)
- self.assertRaises(Exc, cmp, s1, s2)
+ self.assertRaises(Exc, lambda: s1 == s2)
s1 = slice(1, 2, BadCmp())
s2 = slice(1, 2, BadCmp())
self.assertEqual(s1, s1)
- self.assertRaises(Exc, cmp, s1, s2)
+ self.assertRaises(Exc, lambda: s1 == s2)
def test_members(self):
s = slice(1)
diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py
index 84c92cc..031780a 100644
--- a/Lib/test/test_sort.py
+++ b/Lib/test/test_sort.py
@@ -68,8 +68,8 @@ class TestBase(unittest.TestCase):
self.key = key
self.index = i
- def __cmp__(self, other):
- return cmp(self.key, other.key)
+ def __lt__(self, other):
+ return self.key < other.key
def __repr__(self):
return "Stable(%d, %d)" % (self.key, self.index)
@@ -225,6 +225,8 @@ class TestDecorateSortUndecorate(unittest.TestCase):
def __del__(self):
del data[:]
data[:] = range(20)
+ def __lt__(self, other):
+ return id(self) < id(other)
self.assertRaises(ValueError, data.sort, key=SortKiller)
def test_key_with_mutating_del_and_exception(self):
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index 0397118..d260fc5 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -122,8 +122,8 @@ def fcmp(x, y): # fuzzy comparison function
outcome = fcmp(x[i], y[i])
if outcome != 0:
return outcome
- return cmp(len(x), len(y))
- return cmp(x, y)
+ return (len(x) > len(y)) - (len(x) < len(y))
+ return (x > y) - (x < y)
try:
unicode
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index 2d299c3..f0bdfde 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -233,7 +233,6 @@ print 'Buffers'
try: buffer('asdf', -1)
except ValueError: pass
else: raise TestFailed, "buffer('asdf', -1) should raise ValueError"
-cmp(buffer("abc"), buffer("def")) # used to raise a warning: tp_compare didn't return -1, 0, or 1
try: buffer(None)
except TypeError: pass
diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py
index ecb33d1..bc45bf3 100644
--- a/Lib/test/test_userdict.py
+++ b/Lib/test/test_userdict.py
@@ -52,7 +52,7 @@ class UserDictTest(mapping_tests.TestHashMappingProtocol):
all = [d0, d1, d2, u, u0, u1, u2, uu, uu0, uu1, uu2]
for a in all:
for b in all:
- self.assertEqual(cmp(a, b), cmp(len(a), len(b)))
+ self.assertEqual(a == b, len(a) == len(b))
# Test __getitem__
self.assertEqual(u2["one"], 1)
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index a4fb7f3..f5114b2 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -701,6 +701,12 @@ class Object:
self.arg = arg
def __repr__(self):
return "<Object %r>" % self.arg
+ def __lt__(self, other):
+ if isinstance(other, Object):
+ return self.arg < other.arg
+ return NotImplemented
+ def __hash__(self):
+ return hash(self.arg)
class MappingTestCase(TestBase):
diff --git a/Lib/uuid.py b/Lib/uuid.py
index ae3da25..5bf5c35 100644
--- a/Lib/uuid.py
+++ b/Lib/uuid.py
@@ -177,9 +177,36 @@ class UUID(object):
int |= version << 76L
self.__dict__['int'] = int
- def __cmp__(self, other):
+ def __eq__(self, other):
if isinstance(other, UUID):
- return cmp(self.int, other.int)
+ return self.int == other.int
+ return NotImplemented
+
+ def __ne__(self, other):
+ if isinstance(other, UUID):
+ return self.int != other.int
+ return NotImplemented
+
+ # XXX What's the value of being able to sort UUIDs?
+
+ def __lt__(self, other):
+ if isinstance(other, UUID):
+ return self.int < other.int
+ return NotImplemented
+
+ def __gt__(self, other):
+ if isinstance(other, UUID):
+ return self.int > other.int
+ return NotImplemented
+
+ def __le__(self, other):
+ if isinstance(other, UUID):
+ return self.int <= other.int
+ return NotImplemented
+
+ def __ge__(self, other):
+ if isinstance(other, UUID):
+ return self.int >= other.int
return NotImplemented
def __hash__(self):
@@ -488,7 +515,7 @@ def uuid1(node=None, clock_seq=None):
# 0x01b21dd213814000 is the number of 100-ns intervals between the
# UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
- if timestamp <= _last_timestamp:
+ if _last_timestamp is not None and timestamp <= _last_timestamp:
timestamp = _last_timestamp + 1
_last_timestamp = timestamp
if clock_seq is None:
diff --git a/Lib/xmlrpclib.py b/Lib/xmlrpclib.py
index d1bd2d8..72866f1 100644
--- a/Lib/xmlrpclib.py
+++ b/Lib/xmlrpclib.py
@@ -282,56 +282,9 @@ class Fault(Error):
# @param value A boolean value. Any true value is interpreted as True,
# all other values are interpreted as False.
-if _bool_is_builtin:
- boolean = Boolean = bool
- # to avoid breaking code which references xmlrpclib.{True,False}
- True, False = True, False
-else:
- class Boolean:
- """Boolean-value wrapper.
-
- Use True or False to generate a "boolean" XML-RPC value.
- """
-
- def __init__(self, value = 0):
- self.value = operator.truth(value)
-
- def encode(self, out):
- out.write("<value><boolean>%d</boolean></value>\n" % self.value)
-
- def __cmp__(self, other):
- if isinstance(other, Boolean):
- other = other.value
- return cmp(self.value, other)
-
- def __repr__(self):
- if self.value:
- return "<Boolean True at %x>" % id(self)
- else:
- return "<Boolean False at %x>" % id(self)
-
- def __int__(self):
- return self.value
-
- def __nonzero__(self):
- return self.value
-
- True, False = Boolean(1), Boolean(0)
-
- ##
- # Map true or false value to XML-RPC boolean values.
- #
- # @def boolean(value)
- # @param value A boolean value. Any true value is mapped to True,
- # all other values are mapped to False.
- # @return xmlrpclib.True or xmlrpclib.False.
- # @see Boolean
- # @see True
- # @see False
-
- def boolean(value, _truefalse=(False, True)):
- """Convert any Python value to XML-RPC 'boolean'."""
- return _truefalse[operator.truth(value)]
+boolean = Boolean = bool
+# to avoid breaking code which references xmlrpclib.{True,False}
+True, False = True, False
##
# Wrapper for XML-RPC DateTime values. This converts a time value to
@@ -371,10 +324,15 @@ class DateTime:
value = time.strftime("%Y%m%dT%H:%M:%S", value)
self.value = value
- def __cmp__(self, other):
+ def __eq__(self, other):
if isinstance(other, DateTime):
other = other.value
- return cmp(self.value, other)
+ return self.value == other
+
+ def __ne__(self, other):
+ if isinstance(other, DateTime):
+ other = other.value
+ return self.value != other
##
# Get date/time value.
@@ -432,10 +390,15 @@ class Binary:
def __str__(self):
return self.data or ""
- def __cmp__(self, other):
+ def __eq__(self, other):
+ if isinstance(other, Binary):
+ other = other.data
+ return self.data == other
+
+ def __ne__(self, other):
if isinstance(other, Binary):
other = other.data
- return cmp(self.data, other)
+ return self.data != other
def decode(self, data):
self.data = base64.decodestring(data)
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c
index 448b11c..3614296 100644
--- a/Modules/threadmodule.c
+++ b/Modules/threadmodule.c
@@ -696,6 +696,8 @@ initthread(void)
/* Initialize types: */
if (PyType_Ready(&localtype) < 0)
return;
+ if (PyType_Ready(&Locktype) < 0)
+ return;
/* Create the module and add the functions */
m = Py_InitModule3("thread", thread_methods, thread_doc);
diff --git a/Objects/bufferobject.c b/Objects/bufferobject.c
index 3a0e3d5..ddef868 100644
--- a/Objects/bufferobject.c
+++ b/Objects/bufferobject.c
@@ -252,23 +252,65 @@ buffer_dealloc(PyBufferObject *self)
}
static int
-buffer_compare(PyBufferObject *self, PyBufferObject *other)
+get_bufx(PyObject *obj, void **ptr, Py_ssize_t *size)
{
- void *p1, *p2;
- Py_ssize_t len_self, len_other, min_len;
- int cmp;
+ PyBufferProcs *bp;
- if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
- return -1;
- if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
- return -1;
- min_len = (len_self < len_other) ? len_self : len_other;
- if (min_len > 0) {
- cmp = memcmp(p1, p2, min_len);
- if (cmp != 0)
- return cmp < 0 ? -1 : 1;
+ if (PyBuffer_Check(obj)) {
+ if (!get_buf((PyBufferObject *)obj, ptr, size, ANY_BUFFER)) {
+ PyErr_Clear();
+ return 0;
+ }
+ else
+ return 1;
+ }
+ bp = obj->ob_type->tp_as_buffer;
+ if (bp == NULL ||
+ bp->bf_getreadbuffer == NULL ||
+ bp->bf_getsegcount == NULL)
+ return 0;
+ if ((*bp->bf_getsegcount)(obj, NULL) != 1)
+ return 0;
+ *size = (*bp->bf_getreadbuffer)(obj, 0, ptr);
+ if (*size < 0) {
+ PyErr_Clear();
+ return 0;
+ }
+ return 1;
+}
+
+static PyObject *
+buffer_richcompare(PyObject *self, PyObject *other, int op)
+{
+ void *p1, *p2;
+ Py_ssize_t len1, len2, min_len;
+ int cmp, ok;
+
+ ok = 1;
+ if (!get_bufx(self, &p1, &len1))
+ ok = 0;
+ if (!get_bufx(other, &p2, &len2))
+ ok = 0;
+ if (!ok) {
+ /* If we can't get the buffers,
+ == and != are still defined
+ (and the objects are unequal) */
+ PyObject *result;
+ if (op == Py_EQ)
+ result = Py_False;
+ else if (op == Py_NE)
+ result = Py_True;
+ else
+ result = Py_NotImplemented;
+ Py_INCREF(result);
+ return result;
}
- return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
+ min_len = (len1 < len2) ? len1 : len2;
+ cmp = memcmp(p1, p2, min_len);
+ if (cmp == 0)
+ cmp = (len1 < len2) ? -1 :
+ (len1 > len2) ? 1 : 0;
+ return Py_CmpToRich(op, cmp);
}
static PyObject *
@@ -667,7 +709,7 @@ PyTypeObject PyBuffer_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)buffer_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)buffer_repr, /* tp_repr */
0, /* tp_as_number */
&buffer_as_sequence, /* tp_as_sequence */
@@ -682,7 +724,7 @@ PyTypeObject PyBuffer_Type = {
buffer_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ buffer_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/cellobject.c b/Objects/cellobject.c
index 65a29aa..74fa247 100644
--- a/Objects/cellobject.c
+++ b/Objects/cellobject.c
@@ -49,18 +49,6 @@ cell_dealloc(PyCellObject *op)
PyObject_GC_Del(op);
}
-static int
-cell_compare(PyCellObject *a, PyCellObject *b)
-{
- if (a->ob_ref == NULL) {
- if (b->ob_ref == NULL)
- return 0;
- return -1;
- } else if (b->ob_ref == NULL)
- return 1;
- return PyObject_Compare(a->ob_ref, b->ob_ref);
-}
-
static PyObject *
cell_repr(PyCellObject *op)
{
@@ -108,7 +96,7 @@ PyTypeObject PyCell_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)cell_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)cell_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
diff --git a/Objects/classobject.c b/Objects/classobject.c
index cc09960..1107977 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -80,7 +80,7 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *klass)
#define OFF(x) offsetof(PyMethodObject, x)
-static PyMemberDef instancemethod_memberlist[] = {
+static PyMemberDef method_memberlist[] = {
{"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED,
"the class associated with a method"},
{"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED,
@@ -96,7 +96,7 @@ static PyMemberDef instancemethod_memberlist[] = {
should only be used for the class, not for instances */
static PyObject *
-instancemethod_get_doc(PyMethodObject *im, void *context)
+method_get_doc(PyMethodObject *im, void *context)
{
static PyObject *docstr;
if (docstr == NULL) {
@@ -107,13 +107,13 @@ instancemethod_get_doc(PyMethodObject *im, void *context)
return PyObject_GetAttr(im->im_func, docstr);
}
-static PyGetSetDef instancemethod_getset[] = {
- {"__doc__", (getter)instancemethod_get_doc, NULL, NULL},
+static PyGetSetDef method_getset[] = {
+ {"__doc__", (getter)method_get_doc, NULL, NULL},
{0}
};
static PyObject *
-instancemethod_getattro(PyObject *obj, PyObject *name)
+method_getattro(PyObject *obj, PyObject *name)
{
PyMethodObject *im = (PyMethodObject *)obj;
PyTypeObject *tp = obj->ob_type;
@@ -140,19 +140,19 @@ instancemethod_getattro(PyObject *obj, PyObject *name)
return PyObject_GetAttr(im->im_func, name);
}
-PyDoc_STRVAR(instancemethod_doc,
-"instancemethod(function, instance, class)\n\
+PyDoc_STRVAR(method_doc,
+"method(function, instance, class)\n\
\n\
Create an instance method object.");
static PyObject *
-instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw)
+method_new(PyTypeObject* type, PyObject* args, PyObject *kw)
{
PyObject *func;
PyObject *self;
PyObject *classObj = NULL;
- if (!PyArg_UnpackTuple(args, "instancemethod", 2, 3,
+ if (!PyArg_UnpackTuple(args, "method", 2, 3,
&func, &self, &classObj))
return NULL;
if (!PyCallable_Check(func)) {
@@ -172,7 +172,7 @@ instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw)
}
static void
-instancemethod_dealloc(register PyMethodObject *im)
+method_dealloc(register PyMethodObject *im)
{
_PyObject_GC_UNTRACK(im);
if (im->im_weakreflist != NULL)
@@ -184,24 +184,42 @@ instancemethod_dealloc(register PyMethodObject *im)
free_list = im;
}
-static int
-instancemethod_compare(PyMethodObject *a, PyMethodObject *b)
+static PyObject *
+method_richcompare(PyObject *self, PyObject *other, int op)
{
- int cmp;
- cmp = PyObject_Compare(a->im_func, b->im_func);
- if (cmp)
- return cmp;
-
- if (a->im_self == b->im_self)
- return 0;
- if (a->im_self == NULL || b->im_self == NULL)
- return (a->im_self < b->im_self) ? -1 : 1;
+ PyMethodObject *a, *b;
+ PyObject *res;
+ int eq;
+
+ if ((op != Py_EQ && op != Py_NE) ||
+ !PyMethod_Check(self) ||
+ !PyMethod_Check(other))
+ {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ a = (PyMethodObject *)self;
+ b = (PyMethodObject *)other;
+ eq = PyObject_RichCompareBool(a->im_func, b->im_func, Py_EQ);
+ if (eq == 1) {
+ if (a->im_self == NULL || b->im_self == NULL)
+ eq = a->im_self == b->im_self;
+ else
+ eq = PyObject_RichCompareBool(a->im_self, b->im_self,
+ Py_EQ);
+ }
+ if (eq < 0)
+ return NULL;
+ if (op == Py_EQ)
+ res = eq ? Py_True : Py_False;
else
- return PyObject_Compare(a->im_self, b->im_self);
+ res = eq ? Py_False : Py_True;
+ Py_INCREF(res);
+ return res;
}
static PyObject *
-instancemethod_repr(PyMethodObject *a)
+method_repr(PyMethodObject *a)
{
PyObject *self = a->im_self;
PyObject *func = a->im_func;
@@ -261,7 +279,7 @@ instancemethod_repr(PyMethodObject *a)
}
static long
-instancemethod_hash(PyMethodObject *a)
+method_hash(PyMethodObject *a)
{
long x, y;
if (a->im_self == NULL)
@@ -280,7 +298,7 @@ instancemethod_hash(PyMethodObject *a)
}
static int
-instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg)
+method_traverse(PyMethodObject *im, visitproc visit, void *arg)
{
Py_VISIT(im->im_func);
Py_VISIT(im->im_self);
@@ -333,7 +351,7 @@ getinstclassname(PyObject *inst, char *buf, int bufsize)
}
static PyObject *
-instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
+method_call(PyObject *func, PyObject *arg, PyObject *kw)
{
PyObject *self = PyMethod_GET_SELF(func);
PyObject *klass = PyMethod_GET_CLASS(func);
@@ -392,7 +410,7 @@ instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw)
}
static PyObject *
-instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
+method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
{
/* Don't rebind an already bound method, or an unbound method
of a class that's not a base class of cls. */
@@ -420,43 +438,43 @@ instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls)
PyTypeObject PyMethod_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
- "instancemethod",
+ "method",
sizeof(PyMethodObject),
0,
- (destructor)instancemethod_dealloc, /* tp_dealloc */
+ (destructor)method_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)instancemethod_compare, /* tp_compare */
- (reprfunc)instancemethod_repr, /* tp_repr */
+ 0, /* tp_compare */
+ (reprfunc)method_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- (hashfunc)instancemethod_hash, /* tp_hash */
- instancemethod_call, /* tp_call */
+ (hashfunc)method_hash, /* tp_hash */
+ method_call, /* tp_call */
0, /* tp_str */
- instancemethod_getattro, /* tp_getattro */
+ method_getattro, /* tp_getattro */
PyObject_GenericSetAttr, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- instancemethod_doc, /* tp_doc */
- (traverseproc)instancemethod_traverse, /* tp_traverse */
+ method_doc, /* tp_doc */
+ (traverseproc)method_traverse, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ method_richcompare, /* tp_richcompare */
offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
- instancemethod_memberlist, /* tp_members */
- instancemethod_getset, /* tp_getset */
+ method_memberlist, /* tp_members */
+ method_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
- instancemethod_descr_get, /* tp_descr_get */
+ method_descr_get, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
- instancemethod_new, /* tp_new */
+ method_new, /* tp_new */
};
/* Clear out the free list */
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 89871d6..19dcc47 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -291,9 +291,15 @@ code_repr(PyCodeObject *co)
return PyString_FromString(buf);
}
-static int
-code_compare(PyCodeObject *co, PyCodeObject *cp)
+static PyObject *
+code_richcompare(PyObject *self, PyObject *other, int op)
{
+ /* Temporarily make this unsupported */
+ _Py_Break();
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+
+#if 0
int cmp;
cmp = PyObject_Compare(co->co_name, cp->co_name);
if (cmp) return cmp;
@@ -325,6 +331,7 @@ code_compare(PyCodeObject *co, PyCodeObject *cp)
return -1;
else
return 0;
+#endif
}
static long
@@ -363,12 +370,12 @@ PyTypeObject PyCode_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)code_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)code_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- (hashfunc)code_hash, /* tp_hash */
+ 0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index b3fdbf1..320befb 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -582,6 +582,36 @@ PyDict_GetItem(PyObject *op, PyObject *key)
return ep->me_value;
}
+/* Variant of PyDict_GetItem() that doesn't suppress exceptions.
+ This returns NULL *with* an exception set if an exception occurred.
+ It returns NULL *without* an exception set if the key wasn't present.
+*/
+PyObject *
+PyDict_GetItemWithError(PyObject *op, PyObject *key)
+{
+ long hash;
+ dictobject *mp = (dictobject *)op;
+ dictentry *ep;
+
+ if (!PyDict_Check(op)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+ if (!PyString_CheckExact(key) ||
+ (hash = ((PyStringObject *) key)->ob_shash) == -1)
+ {
+ hash = PyObject_Hash(key);
+ if (hash == -1) {
+ return NULL;
+ }
+ }
+
+ ep = (mp->ma_lookup)(mp, key, hash);
+ if (ep == NULL)
+ return NULL;
+ return ep->me_value;
+}
+
/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
* dictionary if it's merely replacing the value for an existing key.
* This means that it's safe to loop over a dictionary with PyDict_Next()
@@ -1432,136 +1462,6 @@ PyDict_Items(PyObject *mp)
return dict_items((dictobject *)mp);
}
-/* Subroutine which returns the smallest key in a for which b's value
- is different or absent. The value is returned too, through the
- pval argument. Both are NULL if no key in a is found for which b's status
- differs. The refcounts on (and only on) non-NULL *pval and function return
- values must be decremented by the caller (characterize() increments them
- to ensure that mutating comparison and PyDict_GetItem calls can't delete
- them before the caller is done looking at them). */
-
-static PyObject *
-characterize(dictobject *a, dictobject *b, PyObject **pval)
-{
- PyObject *akey = NULL; /* smallest key in a s.t. a[akey] != b[akey] */
- PyObject *aval = NULL; /* a[akey] */
- Py_ssize_t i;
- int cmp;
-
- for (i = 0; i <= a->ma_mask; i++) {
- PyObject *thiskey, *thisaval, *thisbval;
- if (a->ma_table[i].me_value == NULL)
- continue;
- thiskey = a->ma_table[i].me_key;
- Py_INCREF(thiskey); /* keep alive across compares */
- if (akey != NULL) {
- cmp = PyObject_RichCompareBool(akey, thiskey, Py_LT);
- if (cmp < 0) {
- Py_DECREF(thiskey);
- goto Fail;
- }
- if (cmp > 0 ||
- i > a->ma_mask ||
- a->ma_table[i].me_value == NULL)
- {
- /* Not the *smallest* a key; or maybe it is
- * but the compare shrunk the dict so we can't
- * find its associated value anymore; or
- * maybe it is but the compare deleted the
- * a[thiskey] entry.
- */
- Py_DECREF(thiskey);
- continue;
- }
- }
-
- /* Compare a[thiskey] to b[thiskey]; cmp <- true iff equal. */
- thisaval = a->ma_table[i].me_value;
- assert(thisaval);
- Py_INCREF(thisaval); /* keep alive */
- thisbval = PyDict_GetItem((PyObject *)b, thiskey);
- if (thisbval == NULL)
- cmp = 0;
- else {
- /* both dicts have thiskey: same values? */
- cmp = PyObject_RichCompareBool(
- thisaval, thisbval, Py_EQ);
- if (cmp < 0) {
- Py_DECREF(thiskey);
- Py_DECREF(thisaval);
- goto Fail;
- }
- }
- if (cmp == 0) {
- /* New winner. */
- Py_XDECREF(akey);
- Py_XDECREF(aval);
- akey = thiskey;
- aval = thisaval;
- }
- else {
- Py_DECREF(thiskey);
- Py_DECREF(thisaval);
- }
- }
- *pval = aval;
- return akey;
-
-Fail:
- Py_XDECREF(akey);
- Py_XDECREF(aval);
- *pval = NULL;
- return NULL;
-}
-
-static int
-dict_compare(dictobject *a, dictobject *b)
-{
- PyObject *adiff, *bdiff, *aval, *bval;
- int res;
-
- /* Compare lengths first */
- if (a->ma_used < b->ma_used)
- return -1; /* a is shorter */
- else if (a->ma_used > b->ma_used)
- return 1; /* b is shorter */
-
- /* Same length -- check all keys */
- bdiff = bval = NULL;
- adiff = characterize(a, b, &aval);
- if (adiff == NULL) {
- assert(!aval);
- /* Either an error, or a is a subset with the same length so
- * must be equal.
- */
- res = PyErr_Occurred() ? -1 : 0;
- goto Finished;
- }
- bdiff = characterize(b, a, &bval);
- if (bdiff == NULL && PyErr_Occurred()) {
- assert(!bval);
- res = -1;
- goto Finished;
- }
- res = 0;
- if (bdiff) {
- /* bdiff == NULL "should be" impossible now, but perhaps
- * the last comparison done by the characterize() on a had
- * the side effect of making the dicts equal!
- */
- res = PyObject_Compare(adiff, bdiff);
- }
- if (res == 0 && bval != NULL)
- res = PyObject_Compare(aval, bval);
-
-Finished:
- Py_XDECREF(adiff);
- Py_XDECREF(bdiff);
- Py_XDECREF(aval);
- Py_XDECREF(bval);
- return res;
-}
-
/* Return 1 if dicts equal, 0 if not, -1 if error.
* Gets out as soon as any difference is detected.
* Uses only Py_EQ comparison.
@@ -1585,9 +1485,11 @@ dict_equal(dictobject *a, dictobject *b)
/* temporarily bump aval's refcount to ensure it stays
alive until we're done with it */
Py_INCREF(aval);
- bval = PyDict_GetItem((PyObject *)b, key);
+ bval = PyDict_GetItemWithError((PyObject *)b, key);
if (bval == NULL) {
Py_DECREF(aval);
+ if (PyErr_Occurred())
+ return -1;
return 0;
}
cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
@@ -2028,7 +1930,7 @@ PyTypeObject PyDict_Type = {
(printfunc)dict_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)dict_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)dict_repr, /* tp_repr */
0, /* tp_as_number */
&dict_as_sequence, /* tp_as_sequence */
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 0ff2321..e64d0b1 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -446,6 +446,17 @@ int_compare(PyIntObject *v, PyIntObject *w)
return (i < j) ? -1 : (i > j) ? 1 : 0;
}
+static PyObject *
+int_richcompare(PyObject *self, PyObject *other, int op)
+{
+ if (!PyInt_Check(self) || !PyInt_Check(other)) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ return Py_CmpToRich(op, int_compare((PyIntObject *)self,
+ (PyIntObject *)other));
+}
+
static long
int_hash(PyIntObject *v)
{
@@ -1063,7 +1074,7 @@ PyTypeObject PyInt_Type = {
(printfunc)int_print, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)int_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)int_repr, /* tp_repr */
&int_as_number, /* tp_as_number */
0, /* tp_as_sequence */
@@ -1078,7 +1089,7 @@ PyTypeObject PyInt_Type = {
int_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ int_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/listobject.c b/Objects/listobject.c
index ab408e9..3d81656 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -1971,6 +1971,26 @@ build_cmpwrapper(PyObject *cmpfunc)
return (PyObject *)co;
}
+static int
+is_default_cmp(PyObject *cmpfunc)
+{
+ PyCFunctionObject *f;
+ if (cmpfunc == NULL || cmpfunc == Py_None)
+ return 1;
+ if (!PyCFunction_Check(cmpfunc))
+ return 0;
+ f = (PyCFunction *)cmpfunc;
+ if (f->m_self != NULL)
+ return 0;
+ if (!PyString_Check(f->m_module))
+ return 0;
+ if (strcmp(PyString_AS_STRING(f->m_module), "__builtin__") != 0)
+ return 0;
+ if (strcmp(f->m_ml->ml_name, "cmp") != 0)
+ return 0;
+ return 1;
+}
+
/* An adaptive, stable, natural mergesort. See listsort.txt.
* Returns Py_None on success, NULL on error. Even in case of error, the
* list will be some permutation of its input state (nothing is lost or
@@ -2001,7 +2021,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds)
kwlist, &compare, &keyfunc, &reverse))
return NULL;
}
- if (compare == Py_None)
+ if (is_default_cmp(compare))
compare = NULL;
if (keyfunc == Py_None)
keyfunc = NULL;
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 16c7043..ab8a8d7 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1,5 +1,3 @@
-
-
/* Long (arbitrary precision) integer object implementation */
/* XXX The functional organization of this file is terrible */
@@ -1882,6 +1880,14 @@ long_compare(PyLongObject *a, PyLongObject *b)
return sign < 0 ? -1 : sign > 0 ? 1 : 0;
}
+static PyObject *
+long_richcompare(PyObject *self, PyObject *other, int op)
+{
+ PyLongObject *a, *b;
+ CONVERT_BINOP((PyObject *)self, (PyObject *)other, &a, &b);
+ return Py_CmpToRich(op, long_compare(a, b));
+}
+
static long
long_hash(PyLongObject *v)
{
@@ -3357,7 +3363,7 @@ PyTypeObject PyLong_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)long_compare, /* tp_compare */
+ 0, /* tp_compare */
long_repr, /* tp_repr */
&long_as_number, /* tp_as_number */
0, /* tp_as_sequence */
@@ -3372,7 +3378,7 @@ PyTypeObject PyLong_Type = {
long_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ long_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index ecc9a0a..862acd1 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -196,17 +196,31 @@ meth_repr(PyCFunctionObject *m)
m->m_self);
}
-static int
-meth_compare(PyCFunctionObject *a, PyCFunctionObject *b)
+static PyObject *
+meth_richcompare(PyObject *self, PyObject *other, int op)
{
- if (a->m_self != b->m_self)
- return (a->m_self < b->m_self) ? -1 : 1;
- if (a->m_ml->ml_meth == b->m_ml->ml_meth)
- return 0;
- if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0)
- return -1;
+ PyCFunctionObject *a, *b;
+ PyObject *res;
+ int eq;
+
+ if ((op != Py_EQ && op != Py_NE) ||
+ !PyCFunction_Check(self) ||
+ !PyCFunction_Check(other))
+ {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
+ a = (PyCFunctionObject *)self;
+ b = (PyCFunctionObject *)other;
+ eq = a->m_self == b->m_self;
+ if (eq)
+ eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
+ if (op == Py_EQ)
+ res = eq ? Py_True : Py_False;
else
- return 1;
+ res = eq ? Py_False : Py_True;
+ Py_INCREF(res);
+ return res;
}
static long
@@ -240,7 +254,7 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)meth_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)meth_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@@ -255,7 +269,7 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_doc */
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ meth_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/object.c b/Objects/object.c
index 80111b4..9bcf08b 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -252,14 +252,6 @@ _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
return PyObject_INIT_VAR(op, tp, nitems);
}
-/* for binary compatibility with 2.2 */
-#undef _PyObject_Del
-void
-_PyObject_Del(PyObject *op)
-{
- PyObject_FREE(op);
-}
-
/* Implementation of PyObject_Print with recursion checking */
static int
internal_print(PyObject *op, FILE *fp, int flags, int nesting)
@@ -513,431 +505,200 @@ PyObject_Unicode(PyObject *v)
#endif
-/* Helper to warn about deprecated tp_compare return values. Return:
- -2 for an exception;
- -1 if v < w;
- 0 if v == w;
- 1 if v > w.
- (This function cannot return 2.)
-*/
-static int
-adjust_tp_compare(int c)
-{
- if (PyErr_Occurred()) {
- if (c != -1 && c != -2) {
- PyObject *t, *v, *tb;
- PyErr_Fetch(&t, &v, &tb);
- if (PyErr_Warn(PyExc_RuntimeWarning,
- "tp_compare didn't return -1 or -2 "
- "for exception") < 0) {
- Py_XDECREF(t);
- Py_XDECREF(v);
- Py_XDECREF(tb);
- }
- else
- PyErr_Restore(t, v, tb);
- }
- return -2;
- }
- else if (c < -1 || c > 1) {
- if (PyErr_Warn(PyExc_RuntimeWarning,
- "tp_compare didn't return -1, 0 or 1") < 0)
- return -2;
- else
- return c < -1 ? -1 : 1;
- }
- else {
- assert(c >= -1 && c <= 1);
- return c;
- }
-}
+/* The new comparison philosophy is: we completely separate three-way
+ comparison from rich comparison. That is, PyObject_Compare() and
+ PyObject_Cmp() *just* use the tp_compare slot. And PyObject_RichCompare()
+ and PyObject_RichCompareBool() *just* use the tp_richcompare slot.
+
+ See (*) below for practical amendments.
+ IOW, only cmp() uses tp_compare; the comparison operators (==, !=, <=, <,
+ >=, >) only use tp_richcompare. Note that list.sort() only uses <.
-/* Macro to get the tp_richcompare field of a type if defined */
-#define RICHCOMPARE(t) ((t)->tp_richcompare)
+ (And yes, eventually we'll rip out cmp() and tp_compare.)
-/* Map rich comparison operators to their swapped version, e.g. LT --> GT */
-int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
+ The calling conventions are different: tp_compare only gets called with two
+ objects of the appropriate type; tp_richcompare gets called with a first
+ argument of the appropriate type and a second object of an arbitrary type.
+ We never do any kind of coercion.
-/* Try a genuine rich comparison, returning an object. Return:
- NULL for exception;
- NotImplemented if this particular rich comparison is not implemented or
- undefined;
- some object not equal to NotImplemented if it is implemented
- (this latter object may not be a Boolean).
-*/
-static PyObject *
-try_rich_compare(PyObject *v, PyObject *w, int op)
-{
- richcmpfunc f;
- PyObject *res;
+ The return conventions are also different.
- if (v->ob_type != w->ob_type &&
- PyType_IsSubtype(w->ob_type, v->ob_type) &&
- (f = RICHCOMPARE(w->ob_type)) != NULL) {
- res = (*f)(w, v, _Py_SwappedOp[op]);
- if (res != Py_NotImplemented)
- return res;
- Py_DECREF(res);
- }
- if ((f = RICHCOMPARE(v->ob_type)) != NULL) {
- res = (*f)(v, w, op);
- if (res != Py_NotImplemented)
- return res;
- Py_DECREF(res);
- }
- if ((f = RICHCOMPARE(w->ob_type)) != NULL) {
- return (*f)(w, v, _Py_SwappedOp[op]);
- }
- res = Py_NotImplemented;
- Py_INCREF(res);
- return res;
-}
+ The tp_compare slot should return a C int, as follows:
-/* Try a genuine rich comparison, returning an int. Return:
- -1 for exception (including the case where try_rich_compare() returns an
- object that's not a Boolean);
- 0 if the outcome is false;
- 1 if the outcome is true;
- 2 if this particular rich comparison is not implemented or undefined.
-*/
-static int
-try_rich_compare_bool(PyObject *v, PyObject *w, int op)
-{
- PyObject *res;
- int ok;
+ -1 if a < b or if an exception occurred
+ 0 if a == b
+ +1 if a > b
- if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL)
- return 2; /* Shortcut, avoid INCREF+DECREF */
- res = try_rich_compare(v, w, op);
- if (res == NULL)
- return -1;
- if (res == Py_NotImplemented) {
- Py_DECREF(res);
- return 2;
- }
- ok = PyObject_IsTrue(res);
- Py_DECREF(res);
- return ok;
-}
+ No other return values are allowed. PyObject_Compare() has the same
+ calling convention.
-/* Try rich comparisons to determine a 3-way comparison. Return:
- -2 for an exception;
- -1 if v < w;
- 0 if v == w;
- 1 if v > w;
- 2 if this particular rich comparison is not implemented or undefined.
-*/
-static int
-try_rich_to_3way_compare(PyObject *v, PyObject *w)
-{
- static struct { int op; int outcome; } tries[3] = {
- /* Try this operator, and if it is true, use this outcome: */
- {Py_EQ, 0},
- {Py_LT, -1},
- {Py_GT, 1},
- };
- int i;
-
- if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL)
- return 2; /* Shortcut */
-
- for (i = 0; i < 3; i++) {
- switch (try_rich_compare_bool(v, w, tries[i].op)) {
- case -1:
- return -2;
- case 1:
- return tries[i].outcome;
- }
- }
+ The tp_richcompare slot should return an object, as follows:
- return 2;
-}
+ NULL if an exception occurred
+ NotImplemented if the requested comparison is not implemented
+ any other false value if the requested comparison is false
+ any other true value if the requested comparison is true
-/* Try a 3-way comparison, returning an int. Return:
- -2 for an exception;
- -1 if v < w;
- 0 if v == w;
- 1 if v > w;
- 2 if this particular 3-way comparison is not implemented or undefined.
-*/
-static int
-try_3way_compare(PyObject *v, PyObject *w)
-{
- int c;
- cmpfunc f;
+ The PyObject_RichCompare[Bool]() wrappers raise TypeError when they get
+ NotImplemented.
- /* Comparisons involving instances are given to instance_compare,
- which has the same return conventions as this function. */
-
- f = v->ob_type->tp_compare;
-
- /* If both have the same (non-NULL) tp_compare, use it. */
- if (f != NULL && f == w->ob_type->tp_compare) {
- c = (*f)(v, w);
- return adjust_tp_compare(c);
- }
-
- /* If either tp_compare is _PyObject_SlotCompare, that's safe. */
- if (f == _PyObject_SlotCompare ||
- w->ob_type->tp_compare == _PyObject_SlotCompare)
- return _PyObject_SlotCompare(v, w);
-
- /* If we're here, v and w,
- a) are not instances;
- b) have different types or a type without tp_compare; and
- c) don't have a user-defined tp_compare.
- tp_compare implementations in C assume that both arguments
- have their type, so we give up if the coercion fails.
- */
- c = PyNumber_CoerceEx(&v, &w);
- if (c < 0)
- return -2;
- if (c > 0)
- return 2;
- f = v->ob_type->tp_compare;
- if (f != NULL && f == w->ob_type->tp_compare) {
- c = (*f)(v, w);
- Py_DECREF(v);
- Py_DECREF(w);
- return adjust_tp_compare(c);
- }
+ (*) Practical amendments:
- /* No comparison defined */
- Py_DECREF(v);
- Py_DECREF(w);
- return 2;
-}
+ - If rich comparison returns NotImplemented, == and != are decided by
+ comparing the object pointer (i.e. falling back to the base object
+ implementation).
+
+ - If three-way comparison is not implemented, it falls back on rich
+ comparison (but not the other way around!).
-/* Final fallback 3-way comparison, returning an int. Return:
- -2 if an error occurred;
- -1 if v < w;
- 0 if v == w;
- 1 if v > w.
*/
-static int
-default_3way_compare(PyObject *v, PyObject *w)
-{
- int c;
- const char *vname, *wname;
- if (v->ob_type == w->ob_type) {
- /* When comparing these pointers, they must be cast to
- * integer types (i.e. Py_uintptr_t, our spelling of C9X's
- * uintptr_t). ANSI specifies that pointer compares other
- * than == and != to non-related structures are undefined.
- */
- Py_uintptr_t vv = (Py_uintptr_t)v;
- Py_uintptr_t ww = (Py_uintptr_t)w;
- return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
- }
+/* Forward */
+static PyObject *do_richcompare(PyObject *v, PyObject *w, int op);
- /* None is smaller than anything */
- if (v == Py_None)
- return -1;
- if (w == Py_None)
- return 1;
-
- /* different type: compare type names; numbers are smaller */
- if (PyNumber_Check(v))
- vname = "";
- else
- vname = v->ob_type->tp_name;
- if (PyNumber_Check(w))
- wname = "";
- else
- wname = w->ob_type->tp_name;
- c = strcmp(vname, wname);
- if (c < 0)
- return -1;
- if (c > 0)
- return 1;
- /* Same type name, or (more likely) incomparable numeric types */
- return ((Py_uintptr_t)(v->ob_type) < (
- Py_uintptr_t)(w->ob_type)) ? -1 : 1;
-}
-
-/* Do a 3-way comparison, by hook or by crook. Return:
- -2 for an exception (but see below);
- -1 if v < w;
- 0 if v == w;
- 1 if v > w;
- BUT: if the object implements a tp_compare function, it returns
- whatever this function returns (whether with an exception or not).
-*/
+/* Perform a three-way comparison, raising TypeError if three-way comparison
+ is not supported. */
static int
-do_cmp(PyObject *v, PyObject *w)
+do_compare(PyObject *v, PyObject *w)
{
- int c;
cmpfunc f;
+ int ok;
- if (v->ob_type == w->ob_type
- && (f = v->ob_type->tp_compare) != NULL) {
- c = (*f)(v, w);
- return adjust_tp_compare(c);
- }
- /* We only get here if one of the following is true:
- a) v and w have different types
- b) v and w have the same type, which doesn't have tp_compare
- c) v and w are instances, and either __cmp__ is not defined or
- __cmp__ returns NotImplemented
- */
- c = try_rich_to_3way_compare(v, w);
- if (c < 2)
- return c;
- c = try_3way_compare(v, w);
- if (c < 2)
- return c;
- return default_3way_compare(v, w);
-}
-
-/* Compare v to w. Return
- -1 if v < w or exception (PyErr_Occurred() true in latter case).
- 0 if v == w.
- 1 if v > w.
- XXX The docs (C API manual) say the return value is undefined in case
- XXX of error.
-*/
+ if (v->ob_type == w->ob_type &&
+ (f = v->ob_type->tp_compare) != NULL) {
+ return (*f)(v, w);
+ }
+
+ /* Now try three-way compare before giving up. This is intentionally
+ elaborate; if you have a it will raise TypeError if it detects two
+ objects that aren't ordered with respect to each other. */
+ ok = PyObject_RichCompareBool(v, w, Py_LT);
+ if (ok < 0)
+ return -1; /* Error */
+ if (ok)
+ return -1; /* Less than */
+ ok = PyObject_RichCompareBool(v, w, Py_GT);
+ if (ok < 0)
+ return -1; /* Error */
+ if (ok)
+ return 1; /* Greater than */
+ ok = PyObject_RichCompareBool(v, w, Py_EQ);
+ if (ok < 0)
+ return -1; /* Error */
+ if (ok)
+ return 0; /* Equal */
+
+ /* Give up */
+ PyErr_Format(PyExc_TypeError,
+ "unorderable types: '%.100s' <> '%.100s'",
+ v->ob_type->tp_name,
+ w->ob_type->tp_name);
+ return -1;
+}
+
+/* Perform a three-way comparison. This wraps do_compare() with a check for
+ NULL arguments and a recursion check. */
int
PyObject_Compare(PyObject *v, PyObject *w)
{
- int result;
+ int res;
if (v == NULL || w == NULL) {
- PyErr_BadInternalCall();
+ if (!PyErr_Occurred())
+ PyErr_BadInternalCall();
return -1;
}
- if (v == w)
- return 0;
if (Py_EnterRecursiveCall(" in cmp"))
return -1;
- result = do_cmp(v, w);
+ res = do_compare(v, w);
Py_LeaveRecursiveCall();
- return result < 0 ? -1 : result;
+ return res < 0 ? -1 : res;
}
-/* Return (new reference to) Py_True or Py_False. */
-static PyObject *
-convert_3way_to_object(int op, int c)
-{
- PyObject *result;
- switch (op) {
- case Py_LT: c = c < 0; break;
- case Py_LE: c = c <= 0; break;
- case Py_EQ: c = c == 0; break;
- case Py_NE: c = c != 0; break;
- case Py_GT: c = c > 0; break;
- case Py_GE: c = c >= 0; break;
- }
- result = c ? Py_True : Py_False;
- Py_INCREF(result);
- return result;
-}
-
-/* We want a rich comparison but don't have one. Try a 3-way cmp instead.
- Return
- NULL if error
- Py_True if v op w
- Py_False if not (v op w)
-*/
-static PyObject *
-try_3way_to_rich_compare(PyObject *v, PyObject *w, int op)
-{
- int c;
+/* Map rich comparison operators to their swapped version, e.g. LT <--> GT */
+int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE};
- c = try_3way_compare(v, w);
- if (c >= 2)
- c = default_3way_compare(v, w);
- if (c <= -2)
- return NULL;
- return convert_3way_to_object(op, c);
-}
+static char *opstrings[] = {">", ">=", "==", "!=", "<", "<="};
-/* Do rich comparison on v and w. Return
- NULL if error
- Else a new reference to an object other than Py_NotImplemented, usually(?):
- Py_True if v op w
- Py_False if not (v op w)
-*/
+/* Perform a rich comparison, raising TypeError when the requested comparison
+ operator is not supported. */
static PyObject *
-do_richcmp(PyObject *v, PyObject *w, int op)
+do_richcompare(PyObject *v, PyObject *w, int op)
{
+ richcmpfunc f;
PyObject *res;
- res = try_rich_compare(v, w, op);
- if (res != Py_NotImplemented)
- return res;
- Py_DECREF(res);
-
- return try_3way_to_rich_compare(v, w, op);
+ if (v->ob_type != w->ob_type &&
+ PyType_IsSubtype(w->ob_type, v->ob_type) &&
+ (f = w->ob_type->tp_richcompare) != NULL) {
+ res = (*f)(w, v, _Py_SwappedOp[op]);
+ if (res != Py_NotImplemented)
+ return res;
+ Py_DECREF(res);
+ }
+ if ((f = v->ob_type->tp_richcompare) != NULL) {
+ res = (*f)(v, w, op);
+ if (res != Py_NotImplemented)
+ return res;
+ Py_DECREF(res);
+ }
+ if ((f = w->ob_type->tp_richcompare) != NULL) {
+ res = (*f)(w, v, _Py_SwappedOp[op]);
+ if (res != Py_NotImplemented)
+ return res;
+ Py_DECREF(res);
+ }
+ /* If neither object implements it, provide a sensible default
+ for == and !=, but raise an exception for ordering. */
+ switch (op) {
+ case Py_EQ:
+ res = (v == w) ? Py_True : Py_False;
+ break;
+ case Py_NE:
+ res = (v != w) ? Py_True : Py_False;
+ break;
+ default:
+ PyErr_Format(PyExc_TypeError,
+ "unorderable types: %.100s() %s %.100s()",
+ v->ob_type->tp_name,
+ opstrings[op],
+ w->ob_type->tp_name);
+ return NULL;
+ }
+ Py_INCREF(res);
+ return res;
}
-/* Return:
- NULL for exception;
- some object not equal to NotImplemented if it is implemented
- (this latter object may not be a Boolean).
-*/
+/* Perform a rich comparison with object result. This wraps do_richcompare()
+ with a check for NULL arguments and a recursion check. */
+
PyObject *
PyObject_RichCompare(PyObject *v, PyObject *w, int op)
{
PyObject *res;
assert(Py_LT <= op && op <= Py_GE);
- if (Py_EnterRecursiveCall(" in cmp"))
+ if (v == NULL || w == NULL) {
+ if (!PyErr_Occurred())
+ PyErr_BadInternalCall();
return NULL;
-
- /* If the types are equal, and not old-style instances, try to
- get out cheap (don't bother with coercions etc.). */
- if (v->ob_type == w->ob_type) {
- cmpfunc fcmp;
- richcmpfunc frich = RICHCOMPARE(v->ob_type);
- /* If the type has richcmp, try it first. try_rich_compare
- tries it two-sided, which is not needed since we've a
- single type only. */
- if (frich != NULL) {
- res = (*frich)(v, w, op);
- if (res != Py_NotImplemented)
- goto Done;
- Py_DECREF(res);
- }
- /* No richcmp, or this particular richmp not implemented.
- Try 3-way cmp. */
- fcmp = v->ob_type->tp_compare;
- if (fcmp != NULL) {
- int c = (*fcmp)(v, w);
- c = adjust_tp_compare(c);
- if (c == -2) {
- res = NULL;
- goto Done;
- }
- res = convert_3way_to_object(op, c);
- goto Done;
- }
}
-
- /* Fast path not taken, or couldn't deliver a useful result. */
- res = do_richcmp(v, w, op);
-Done:
+ if (Py_EnterRecursiveCall(" in cmp"))
+ return NULL;
+ res = do_richcompare(v, w, op);
Py_LeaveRecursiveCall();
return res;
}
-/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
+/* Perform a rich comparison with integer result. This wraps
+ PyObject_RichCompare(), returning -1 for error, 0 for false, 1 for true. */
int
PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
{
PyObject *res;
int ok;
- /* Quick result when objects are the same.
- Guarantees that identity implies equality. */
- if (v == w) {
- if (op == Py_EQ)
- return 1;
- else if (op == Py_NE)
- return 0;
- }
-
res = PyObject_RichCompare(v, w, op);
if (res == NULL)
return -1;
@@ -949,6 +710,44 @@ PyObject_RichCompareBool(PyObject *v, PyObject *w, int op)
return ok;
}
+/* Turn the result of a three-way comparison into the result expected by a
+ rich comparison. */
+PyObject *
+Py_CmpToRich(int op, int cmp)
+{
+ PyObject *res;
+ int ok;
+
+ if (PyErr_Occurred())
+ return NULL;
+ switch (op) {
+ case Py_LT:
+ ok = cmp < 0;
+ break;
+ case Py_LE:
+ ok = cmp <= 0;
+ break;
+ case Py_EQ:
+ ok = cmp == 0;
+ break;
+ case Py_NE:
+ ok = cmp != 0;
+ break;
+ case Py_GT:
+ ok = cmp > 0;
+ break;
+ case Py_GE:
+ ok = cmp >= 0;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
+ }
+ res = ok ? Py_True : Py_False;
+ Py_INCREF(res);
+ return res;
+}
+
/* Set of hash utility functions to help maintaining the invariant that
if a==b then hash(a)==hash(b)
@@ -1832,6 +1631,9 @@ _Py_ReadyTypes(void)
if (PyType_Ready(&PyNotImplemented_Type) < 0)
Py_FatalError("Can't initialize type(NotImplemented)");
+
+ if (PyType_Ready(&PyCode_Type) < 0)
+ Py_FatalError("Can't initialize 'code'");
}
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index d8a2465..0075a4e 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -280,25 +280,55 @@ static PyMethodDef slice_methods[] = {
{NULL, NULL}
};
-static int
-slice_compare(PySliceObject *v, PySliceObject *w)
+static PyObject *
+slice_richcompare(PyObject *v, PyObject *w, int op)
{
- int result = 0;
-
- if (v == w)
- return 0;
-
- if (PyObject_Cmp(v->start, w->start, &result) < 0)
- return -2;
- if (result != 0)
- return result;
- if (PyObject_Cmp(v->stop, w->stop, &result) < 0)
- return -2;
- if (result != 0)
- return result;
- if (PyObject_Cmp(v->step, w->step, &result) < 0)
- return -2;
- return result;
+ PyObject *t1;
+ PyObject *t2;
+ PyObject *res;
+
+ if (v == w) {
+ /* XXX Do we really need this shortcut?
+ There's a unit test for it, but is that fair? */
+ switch (op) {
+ case Py_EQ:
+ case Py_LE:
+ case Py_GE:
+ res = Py_True;
+ break;
+ default:
+ res = Py_False;
+ break;
+ }
+ Py_INCREF(res);
+ return res;
+ }
+
+ t1 = PyTuple_New(3);
+ t2 = PyTuple_New(3);
+ if (t1 == NULL || t2 == NULL)
+ return NULL;
+
+ PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
+ PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
+ PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
+ PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
+ PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
+ PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
+
+ res = PyObject_RichCompare(t1, t2, op);
+
+ PyTuple_SET_ITEM(t1, 0, NULL);
+ PyTuple_SET_ITEM(t1, 1, NULL);
+ PyTuple_SET_ITEM(t1, 2, NULL);
+ PyTuple_SET_ITEM(t2, 0, NULL);
+ PyTuple_SET_ITEM(t2, 1, NULL);
+ PyTuple_SET_ITEM(t2, 2, NULL);
+
+ Py_DECREF(t1);
+ Py_DECREF(t2);
+
+ return res;
}
static long
@@ -318,7 +348,7 @@ PyTypeObject PySlice_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- (cmpfunc)slice_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)slice_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
@@ -333,7 +363,7 @@ PyTypeObject PySlice_Type = {
slice_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ slice_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index d19801f..d16c6b4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -361,16 +361,6 @@ static PyGetSetDef type_getsets[] = {
{0}
};
-static int
-type_compare(PyObject *v, PyObject *w)
-{
- /* This is called with type objects only. So we
- can just compare the addresses. */
- Py_uintptr_t vv = (Py_uintptr_t)v;
- Py_uintptr_t ww = (Py_uintptr_t)w;
- return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
-}
-
static PyObject *
type_repr(PyTypeObject *type)
{
@@ -2192,12 +2182,12 @@ PyTypeObject PyType_Type = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- type_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)type_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
- (hashfunc)_Py_HashPointer, /* tp_hash */
+ 0, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
0, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
@@ -2302,6 +2292,30 @@ object_str(PyObject *self)
}
static PyObject *
+object_richcompare(PyObject *self, PyObject *other, int op)
+{
+ PyObject *res;
+
+ switch (op) {
+
+ case Py_EQ:
+ res = (self == other) ? Py_True : Py_False;
+ break;
+
+ case Py_NE:
+ res = (self != other) ? Py_True : Py_False;
+ break;
+
+ default:
+ res = Py_NotImplemented;
+ break;
+ }
+
+ Py_INCREF(res);
+ return res;
+}
+
+static PyObject *
object_get_class(PyObject *self, void *closure)
{
Py_INCREF(self->ob_type);
@@ -2703,7 +2717,7 @@ PyTypeObject PyBaseObject_Type = {
PyDoc_STR("The most base type"), /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
- 0, /* tp_richcompare */
+ object_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index f814306..206a455 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -184,7 +184,9 @@ weakref_repr(PyWeakReference *self)
static PyObject *
weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
{
- if (op != Py_EQ || self->ob_type != other->ob_type) {
+ if ((op != Py_EQ && op != Py_NE) ||
+ !PyWeakref_Check(self) ||
+ !PyWeakref_Check(other)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
@@ -458,12 +460,12 @@ proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value);
}
-static int
-proxy_compare(PyObject *proxy, PyObject *v)
+static PyObject *
+proxy_richcompare(PyObject *proxy, PyObject *v, int op)
{
- UNWRAP_I(proxy);
- UNWRAP_I(v);
- return PyObject_Compare(proxy, v);
+ UNWRAP(proxy);
+ UNWRAP(v);
+ return PyObject_RichCompare(proxy, v, op);
}
/* number slots */
@@ -649,7 +651,7 @@ _PyWeakref_ProxyType = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- proxy_compare, /* tp_compare */
+ 0, /* tp_compare */
(reprfunc)proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
@@ -664,7 +666,7 @@ _PyWeakref_ProxyType = {
0, /* tp_doc */
(traverseproc)gc_traverse, /* tp_traverse */
(inquiry)gc_clear, /* tp_clear */
- 0, /* tp_richcompare */
+ proxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)proxy_iter, /* tp_iter */
(iternextfunc)proxy_iternext, /* tp_iternext */
@@ -683,7 +685,7 @@ _PyWeakref_CallableProxyType = {
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
- proxy_compare, /* tp_compare */
+ 0, /* tp_compare */
(unaryfunc)proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */
@@ -698,7 +700,7 @@ _PyWeakref_CallableProxyType = {
0, /* tp_doc */
(traverseproc)gc_traverse, /* tp_traverse */
(inquiry)gc_clear, /* tp_clear */
- 0, /* tp_richcompare */
+ proxy_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)proxy_iter, /* tp_iter */
(iternextfunc)proxy_iternext, /* tp_iternext */
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 16758d7..6309624 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -1324,9 +1324,10 @@ get_len_of_range_longs(PyObject *lo, PyObject *hi, PyObject *step)
PyObject *tmp1 = NULL, *tmp2 = NULL, *tmp3 = NULL;
/* holds sub-expression evaluations */
- /* if (lo >= hi), return length of 0. */
- if (PyObject_Compare(lo, hi) >= 0)
- return 0;
+ /* If (lo >= hi), return length of 0 (or error). */
+ n = PyObject_RichCompareBool(lo, hi, Py_LT);
+ if (n <= 0)
+ return n;
if ((one = PyLong_FromLong(1L)) == NULL)
goto Fail;
@@ -1378,7 +1379,7 @@ handle_range_longs(PyObject *self, PyObject *args)
PyObject *v = NULL;
long bign;
int i, n;
- int cmp_result;
+ int step_pos;
PyObject *zero = PyLong_FromLong(0);
@@ -1439,17 +1440,20 @@ handle_range_longs(PyObject *self, PyObject *args)
goto Fail;
}
- if (PyObject_Cmp(istep, zero, &cmp_result) == -1)
+ step_pos = PyObject_RichCompareBool(istep, zero, Py_GT);
+ if (step_pos < 0)
goto Fail;
- if (cmp_result == 0) {
- PyErr_SetString(PyExc_ValueError,
- "range() step argument must not be zero");
- goto Fail;
- }
-
- if (cmp_result > 0)
+ if (step_pos)
bign = get_len_of_range_longs(ilow, ihigh, istep);
else {
+ int step_zero = PyObject_RichCompareBool(istep, zero, Py_EQ);
+ if (step_zero < 0)
+ goto Fail;
+ if (step_zero) {
+ PyErr_SetString(PyExc_ValueError,
+ "range() step argument must not be zero");
+ goto Fail;
+ }
PyObject *neg_istep = PyNumber_Negative(istep);
if (neg_istep == NULL)
goto Fail;