From a56c467ac39ab1a6a2e9dc2fa41a9f573f989839 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Tue, 27 Jan 2009 18:17:45 +0000 Subject: Issue #1717: Remove cmp. Stage 1: remove all uses of cmp and __cmp__ from the standard library and tests. --- Lib/collections.py | 2 -- Lib/ctypes/test/test_libc.py | 6 +++- Lib/distutils/version.py | 63 ++++++++++++++++++++---------------- Lib/heapq.py | 2 +- Lib/locale.py | 2 +- Lib/pydoc.py | 2 +- Lib/sqlite3/test/hooks.py | 10 +++--- Lib/test/crashers/loosing_mro_ref.py | 4 +-- Lib/test/list_tests.py | 22 +++++++++++-- Lib/test/test_builtin.py | 23 +++---------- Lib/test/test_contains.py | 21 ++---------- Lib/test/test_copy.py | 17 +++++++--- Lib/test/test_datetime.py | 36 ++++----------------- Lib/test/test_decimal.py | 6 ---- Lib/test/test_deque.py | 1 - Lib/test/test_descr.py | 40 +++++++---------------- Lib/test/test_dict.py | 2 +- Lib/test/test_hash.py | 6 ---- Lib/test/test_heapq.py | 4 +-- Lib/test/test_hmac.py | 2 +- Lib/test/test_kqueue.py | 9 +++--- Lib/test/test_long.py | 7 ++-- Lib/test/test_set.py | 10 ------ Lib/test/test_sort.py | 21 ++++++++---- Lib/test/test_unittest.py | 22 +++++++++---- Lib/test/test_userdict.py | 2 +- Lib/test/test_uuid.py | 7 +++- Lib/unittest.py | 6 +++- Lib/xml/dom/minidom.py | 22 +++++++++++-- Lib/xml/etree/ElementTree.py | 26 +++++++++++++-- Lib/xmlrpc/client.py | 4 --- Tools/unicode/makeunicodedata.py | 19 ++--------- 32 files changed, 210 insertions(+), 216 deletions(-) diff --git a/Lib/collections.py b/Lib/collections.py index 4bde5b3..512cf28 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -436,8 +436,6 @@ class UserList(MutableSequence): def __ge__(self, other): return self.data >= self.__cast(other) def __cast(self, other): return other.data if isinstance(other, UserList) else other - def __cmp__(self, other): - return cmp(self.data, self.__cast(other)) def __contains__(self, item): return item in self.data def __len__(self): return len(self.data) def __getitem__(self, i): return self.data[i] diff --git a/Lib/ctypes/test/test_libc.py b/Lib/ctypes/test/test_libc.py index b204fae..fa4c0c9 100644 --- a/Lib/ctypes/test/test_libc.py +++ b/Lib/ctypes/test/test_libc.py @@ -5,6 +5,10 @@ import _ctypes_test lib = CDLL(_ctypes_test.__file__) +def three_way_cmp(x, y): + """Return -1 if x < y, 0 if x == y and 1 if x > y""" + return (x > y) - (x < y) + class LibTest(unittest.TestCase): def test_sqrt(self): lib.my_sqrt.argtypes = c_double, @@ -19,7 +23,7 @@ class LibTest(unittest.TestCase): lib.my_qsort.restype = None def sort(a, b): - return cmp(a[0], b[0]) + return three_way_cmp(a[0], b[0]) chars = create_string_buffer("spam, spam, and spam") lib.my_qsort(chars, len(chars)-1, sizeof(c_char), comparefunc(sort)) diff --git a/Lib/distutils/version.py b/Lib/distutils/version.py index 907f71c..7781437 100644 --- a/Lib/distutils/version.py +++ b/Lib/distutils/version.py @@ -21,7 +21,7 @@ Every version number class implements the following interface: an equivalent string -- ie. one that will generate an equivalent version number instance) * __repr__ generates Python code to recreate the version number instance - * __cmp__ compares the current instance with either another instance + * _cmp compares the current instance with either another instance of the same class or a string (which will be parsed to an instance of the same class, thus must follow the same rules) """ @@ -32,7 +32,7 @@ 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; and route - rich comparisons to __cmp__. + rich comparisons to _cmp. """ def __init__ (self, vstring=None): @@ -43,37 +43,37 @@ class Version: return "%s ('%s')" % (self.__class__.__name__, str(self)) def __eq__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c == 0 def __ne__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c != 0 def __lt__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c < 0 def __le__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c <= 0 def __gt__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c > 0 def __ge__(self, other): - c = self.__cmp__(other) + c = self._cmp(other) if c is NotImplemented: return c return c >= 0 @@ -91,7 +91,7 @@ class Version: # (if not identical to) the string supplied to parse # __repr__ (self) - generate Python code to recreate # the instance -# __cmp__ (self, other) - compare two version numbers ('other' may +# _cmp (self, other) - compare two version numbers ('other' may # be an unparsed version string, or another # instance of your version class) @@ -169,30 +169,39 @@ class StrictVersion (Version): return vstring - def __cmp__ (self, other): + def _cmp (self, other): if isinstance(other, str): other = StrictVersion(other) - compare = cmp(self.version, other.version) - if (compare == 0): # have to compare prerelease - - # case 1: neither has prerelease; they're equal - # case 2: self has prerelease, other doesn't; other is greater - # case 3: self doesn't have prerelease, other does: self is greater - # case 4: both have prerelease: must compare them! + if self.version != other.version: + # numeric versions don't match + # prerelease stuff doesn't matter + if self.version < other.version: + return -1 + else: + return 1 - if (not self.prerelease and not other.prerelease): + # have to compare prerelease + # case 1: neither has prerelease; they're equal + # case 2: self has prerelease, other doesn't; other is greater + # case 3: self doesn't have prerelease, other does: self is greater + # case 4: both have prerelease: must compare them! + + if (not self.prerelease and not other.prerelease): + return 0 + elif (self.prerelease and not other.prerelease): + return -1 + elif (not self.prerelease and other.prerelease): + return 1 + elif (self.prerelease and other.prerelease): + if self.prerelease == other.prerelease: return 0 - elif (self.prerelease and not other.prerelease): + elif self.prerelease < other.prerelease: return -1 - elif (not self.prerelease and other.prerelease): + else: return 1 - elif (self.prerelease and other.prerelease): - return cmp(self.prerelease, other.prerelease) - - else: # numeric versions don't match -- - return compare # prerelease stuff doesn't matter - + else: + assert False, "never get here" # end class StrictVersion @@ -325,7 +334,7 @@ class LooseVersion (Version): return "LooseVersion ('%s')" % str(self) - def __cmp__ (self, other): + def _cmp (self, other): if isinstance(other, str): other = LooseVersion(other) diff --git a/Lib/heapq.py b/Lib/heapq.py index 192e982..ff4fc03 100644 --- a/Lib/heapq.py +++ b/Lib/heapq.py @@ -262,7 +262,7 @@ def _siftdown(heap, startpos, pos): # # Cutting the # of comparisons is important, since these routines have no # way to extract "the priority" from an array element, so that intelligence -# is likely to be hiding in custom __cmp__ methods, or in array elements +# is likely to be hiding in custom comparison methods, or in array elements # storing (priority, record) tuples. Comparisons are thus potentially # expensive. # diff --git a/Lib/locale.py b/Lib/locale.py index 4116ef1..62828fd 100644 --- a/Lib/locale.py +++ b/Lib/locale.py @@ -31,7 +31,7 @@ def _strcoll(a,b): """ strcoll(string,string) -> int. Compares two strings according to the locale. """ - return cmp(a,b) + return (a > b) - (a < b) def _strxfrm(s): """ strxfrm(string) -> string. diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 208e85e..2aea8c0 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1643,7 +1643,7 @@ class Helper: 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS ' 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS ' 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'), - 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'), + 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'), 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'), 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'), 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 ' diff --git a/Lib/sqlite3/test/hooks.py b/Lib/sqlite3/test/hooks.py index 6872fd6..c15c7be 100644 --- a/Lib/sqlite3/test/hooks.py +++ b/Lib/sqlite3/test/hooks.py @@ -42,7 +42,7 @@ class CollationTests(unittest.TestCase): def CheckCreateCollationNotAscii(self): con = sqlite.connect(":memory:") try: - con.create_collation("collä", cmp) + con.create_collation("collä", lambda x, y: (x > y) - (x < y)) self.fail("should have raised a ProgrammingError") except sqlite.ProgrammingError as e: pass @@ -52,7 +52,7 @@ class CollationTests(unittest.TestCase): return def mycoll(x, y): # reverse order - return -cmp(x, y) + return -((x > y) - (x < y)) con = sqlite.connect(":memory:") con.create_collation("mycoll", mycoll) @@ -82,8 +82,8 @@ class CollationTests(unittest.TestCase): Verify that the last one is actually used. """ con = sqlite.connect(":memory:") - con.create_collation("mycoll", cmp) - con.create_collation("mycoll", lambda x, y: -cmp(x, y)) + con.create_collation("mycoll", lambda x, y: (x > y) - (x < y)) + con.create_collation("mycoll", lambda x, y: -((x > y) - (x < y))) result = con.execute(""" select x from (select 'a' as x union select 'b' as x) order by x collate mycoll """).fetchall() @@ -96,7 +96,7 @@ class CollationTests(unittest.TestCase): to use it. """ con = sqlite.connect(":memory:") - con.create_collation("mycoll", cmp) + con.create_collation("mycoll", lambda x, y: (x > y) - (x < y)) con.create_collation("mycoll", None) try: con.execute("select 'a' as x union select 'b' as x order by x collate mycoll") diff --git a/Lib/test/crashers/loosing_mro_ref.py b/Lib/test/crashers/loosing_mro_ref.py index a8c6e63..b3bcd32 100644 --- a/Lib/test/crashers/loosing_mro_ref.py +++ b/Lib/test/crashers/loosing_mro_ref.py @@ -10,7 +10,7 @@ class MyKey(object): def __hash__(self): return hash('mykey') - def __cmp__(self, other): + def __eq__(self, other): # the following line decrefs the previous X.__mro__ X.__bases__ = (Base2,) # trash all tuples of length 3, to make sure that the items of @@ -18,7 +18,7 @@ class MyKey(object): z = [] for i in range(1000): z.append((i, None, None)) - return -1 + return 0 class Base(object): diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index 5b1aa75..67492f3 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -439,13 +439,24 @@ class CommonTest(seq_tests.CommonTest): self.assertRaises(TypeError, u.sort, 42, 42) def revcmp(a, b): - return cmp(b, a) + if a == b: + return 0 + elif a < b: + return 1 + else: # a > b + return -1 u.sort(key=CmpToKey(revcmp)) self.assertEqual(u, self.type2test([2,1,0,-1,-2])) # The following dumps core in unpatched Python 1.5: def myComparison(x,y): - return cmp(x%3, y%7) + xmod, ymod = x%3, y%7 + if xmod == ymod: + return 0 + elif xmod < ymod: + return -1 + else: # xmod > ymod + return 1 z = self.type2test(range(12)) z.sort(key=CmpToKey(myComparison)) @@ -453,7 +464,12 @@ class CommonTest(seq_tests.CommonTest): def selfmodifyingComparison(x,y): z.append(1) - return cmp(x, y) + if x == y: + return 0 + elif x < y: + return -1 + else: # x > y + return 1 self.assertRaises(ValueError, z.sort, key=CmpToKey(selfmodifyingComparison)) self.assertRaises(TypeError, z.sort, 42, 42, 42, 42) diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index 7175b80..99785dc 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -10,6 +10,7 @@ warnings.filterwarnings("ignore", "hex../oct.. of negative int", FutureWarning, __name__) warnings.filterwarnings("ignore", "integer argument expected", DeprecationWarning, "unittest") +import builtins class Squares: @@ -219,21 +220,9 @@ class BuiltinTest(unittest.TestCase): self.assertRaises((OverflowError, ValueError), chr, 2**32) def test_cmp(self): - self.assertEqual(cmp(-1, 1), -1) - self.assertEqual(cmp(1, -1), 1) - self.assertEqual(cmp(1, 1), 0) - # verify that circular objects are not handled - a = []; a.append(a) - b = []; b.append(b) - from collections import UserList - c = UserList(); c.append(c) - self.assertRaises(RuntimeError, cmp, a, b) - self.assertRaises(RuntimeError, cmp, b, c) - self.assertRaises(RuntimeError, cmp, c, a) - self.assertRaises(RuntimeError, cmp, a, c) - # okay, now break the cycles - a.pop(); b.pop(); c.pop() - self.assertRaises(TypeError, cmp) + # uncomment the following line once cmp has been removed + #self.assert_(not hasattr(builtins, "cmp")) + pass def test_compile(self): compile('print(1)\n', '', 'exec') @@ -736,10 +725,6 @@ class BuiltinTest(unittest.TestCase): def __getitem__(self, index): raise ValueError self.assertRaises(ValueError, min, BadSeq()) - class BadNumber: - def __cmp__(self, other): - raise ValueError - self.assertRaises(TypeError, min, (42, BadNumber())) for stmt in ( "min(key=int)", # no args diff --git a/Lib/test/test_contains.py b/Lib/test/test_contains.py index 39c61bd..3f0b234 100644 --- a/Lib/test/test_contains.py +++ b/Lib/test/test_contains.py @@ -56,31 +56,16 @@ class TestContains(unittest.TestCase): This class is designed to make sure that the contains code works when the list is modified during the check. """ - aList = range(15) - def __cmp__(self, other): + aList = list(range(15)) + def __eq__(self, other): if other == 12: self.aList.remove(12) self.aList.remove(13) self.aList.remove(14) - return 1 + return 0 self.assert_(Deviant1() not in Deviant1.aList) - class Deviant2: - """Behaves strangely when compared - - This class raises an exception during comparison. That in - turn causes the comparison to fail with a TypeError. - """ - def __cmp__(self, other): - if other == 4: - raise RuntimeError("gotcha") - - try: - self.assert_(Deviant2() not in a) - except TypeError: - pass - def test_nonreflexive(self): # containment and equality tests involving elements that are # not necessarily equal to themselves diff --git a/Lib/test/test_copy.py b/Lib/test/test_copy.py index 500fa83..133c888 100644 --- a/Lib/test/test_copy.py +++ b/Lib/test/test_copy.py @@ -2,10 +2,14 @@ import copy import copyreg - +from operator import le, lt, ge, gt, eq, ne import unittest from test import support +order_comparisons = le, lt, ge, gt +equality_comparisons = eq, ne +comparisons = order_comparisons + equality_comparisons + class TestCopy(unittest.TestCase): # Attempt full line coverage of copy.py from top to bottom @@ -271,7 +275,8 @@ class TestCopy(unittest.TestCase): x = [] x.append(x) y = copy.deepcopy(x) - self.assertRaises(RuntimeError, cmp, y, x) + for op in comparisons: + self.assertRaises(RuntimeError, op, y, x) self.assert_(y is not x) self.assert_(y[0] is y) self.assertEqual(len(y), 1) @@ -287,7 +292,8 @@ class TestCopy(unittest.TestCase): x = ([],) x[0].append(x) y = copy.deepcopy(x) - self.assertRaises(RuntimeError, cmp, y, x) + for op in comparisons: + self.assertRaises(RuntimeError, op, y, x) self.assert_(y is not x) self.assert_(y[0] is not x[0]) self.assert_(y[0][0] is y) @@ -303,7 +309,10 @@ class TestCopy(unittest.TestCase): x = {} x['foo'] = x y = copy.deepcopy(x) - self.assertRaises(TypeError, cmp, y, x) + for op in order_comparisons: + self.assertRaises(TypeError, op, y, x) + for op in equality_comparisons: + self.assertRaises(RuntimeError, op, y, x) self.assert_(y is not x) self.assert_(y['foo'] is y) self.assertEqual(len(y), 1) diff --git a/Lib/test/test_datetime.py b/Lib/test/test_datetime.py index 797800f..b9d5959 100644 --- a/Lib/test/test_datetime.py +++ b/Lib/test/test_datetime.py @@ -7,6 +7,8 @@ import os import pickle import unittest +from operator import lt, le, gt, ge, eq, ne + from test import support from datetime import MINYEAR, MAXYEAR @@ -156,9 +158,6 @@ class HarmlessMixedComparison: self.assertRaises(TypeError, lambda: () > me) self.assertRaises(TypeError, lambda: () >= me) - self.assertRaises(TypeError, cmp, (), me) - self.assertRaises(TypeError, cmp, me, ()) - ############################################################################# # timedelta tests @@ -309,8 +308,6 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t1 != t2) self.failUnless(not t1 < t2) self.failUnless(not t1 > t2) - self.assertEqual(cmp(t1, t2), 0) - self.assertEqual(cmp(t2, t1), 0) for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): t2 = timedelta(*args) # this is larger than t1 @@ -326,8 +323,6 @@ class TestTimeDelta(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t2 < t1) self.failUnless(not t1 >= t2) self.failUnless(not t2 <= t1) - self.assertEqual(cmp(t1, t2), -1) - self.assertEqual(cmp(t2, t1), 1) for badarg in OTHERSTUFF: self.assertEqual(t1 == badarg, False) @@ -953,8 +948,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t1 != t2) self.failUnless(not t1 < t2) self.failUnless(not t1 > t2) - self.assertEqual(cmp(t1, t2), 0) - self.assertEqual(cmp(t2, t1), 0) for args in (3, 3, 3), (2, 4, 4), (2, 3, 5): t2 = self.theclass(*args) # this is larger than t1 @@ -970,8 +963,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t2 < t1) self.failUnless(not t1 >= t2) self.failUnless(not t2 <= t1) - self.assertEqual(cmp(t1, t2), -1) - self.assertEqual(cmp(t2, t1), 1) for badarg in OTHERSTUFF: self.assertEqual(t1 == badarg, False) @@ -999,8 +990,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): # But the ordering is undefined self.assertRaises(TypeError, lambda: our < 1) self.assertRaises(TypeError, lambda: 1 < our) - self.assertRaises(TypeError, cmp, our, 1) - self.assertRaises(TypeError, cmp, 1, our) # Repeat those tests with a different class @@ -1014,8 +1003,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): self.assertEqual(their != our, True) self.assertRaises(TypeError, lambda: our < their) self.assertRaises(TypeError, lambda: their < our) - self.assertRaises(TypeError, cmp, our, their) - self.assertRaises(TypeError, cmp, their, our) # However, if the other class explicitly defines ordering # relative to our class, it is allowed to do so @@ -1041,8 +1028,6 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase): self.assertEqual(their != our, True) self.assertEqual(our < their, True) self.assertEqual(their < our, False) - self.assertEqual(cmp(our, their), -1) - self.assertEqual(cmp(their, our), 1) def test_bool(self): # All dates are considered true. @@ -1440,8 +1425,6 @@ class TestDateTime(TestDate): self.failUnless(not t1 != t2) self.failUnless(not t1 < t2) self.failUnless(not t1 > t2) - self.assertEqual(cmp(t1, t2), 0) - self.assertEqual(cmp(t2, t1), 0) for i in range(len(args)): newargs = args[:] @@ -1459,8 +1442,6 @@ class TestDateTime(TestDate): self.failUnless(not t2 < t1) self.failUnless(not t1 >= t2) self.failUnless(not t2 <= t1) - self.assertEqual(cmp(t1, t2), -1) - self.assertEqual(cmp(t2, t1), 1) # A helper for timestamp constructor tests. @@ -1728,8 +1709,6 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t1 != t2) self.failUnless(not t1 < t2) self.failUnless(not t1 > t2) - self.assertEqual(cmp(t1, t2), 0) - self.assertEqual(cmp(t2, t1), 0) for i in range(len(args)): newargs = args[:] @@ -1747,8 +1726,6 @@ class TestTime(HarmlessMixedComparison, unittest.TestCase): self.failUnless(not t2 < t1) self.failUnless(not t1 >= t2) self.failUnless(not t2 <= t1) - self.assertEqual(cmp(t1, t2), -1) - self.assertEqual(cmp(t2, t1), 1) for badarg in OTHERSTUFF: self.assertEqual(t1 == badarg, False) @@ -2122,9 +2099,10 @@ class TZInfoBase: d2 = base.replace(minute=11) for x in d0, d1, d2: for y in d0, d1, d2: - got = cmp(x, y) - expected = cmp(x.minute, y.minute) - self.assertEqual(got, expected) + for op in lt, le, gt, ge, eq, ne: + got = op(x, y) + expected = op(x.minute, y.minute) + self.assertEqual(got, expected) # However, if they're different members, uctoffset is not ignored. # Note that a time can't actually have an operand-depedent offset, @@ -2136,7 +2114,7 @@ class TZInfoBase: d2 = base.replace(minute=11, tzinfo=OperandDependentOffset()) for x in d0, d1, d2: for y in d0, d1, d2: - got = cmp(x, y) + got = (x > y) - (x < y) if (x is d0 or x is d1) and (y is d0 or y is d1): expected = 0 elif x is y is d2: diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 9643804..798f4d8 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1012,17 +1012,11 @@ class DecimalUsabilityTest(unittest.TestCase): self.failUnless(da != dc) self.failUnless(da <= db) self.failUnless(da >= db) - self.assertEqual(cmp(dc,da), 1) - self.assertEqual(cmp(da,dc), -1) - self.assertEqual(cmp(da,db), 0) #a Decimal and an int self.failUnless(dc > 23) self.failUnless(23 < dc) self.assertEqual(dc, 45) - self.assertEqual(cmp(dc,23), 1) - self.assertEqual(cmp(23,dc), -1) - self.assertEqual(cmp(dc,45), 0) #a Decimal and uncomparable self.assertNotEqual(da, 'ugly') diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index 27c89c4..5d975f6 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -103,7 +103,6 @@ class TestBasic(unittest.TestCase): self.assertEqual(x <= y, list(x) <= list(y), (x,y)) self.assertEqual(x > y, list(x) > list(y), (x,y)) self.assertEqual(x >= y, list(x) >= list(y), (x,y)) - self.assertEqual(cmp(x,y), cmp(list(x),list(y)), (x,y)) def test_extend(self): d = deque('a') diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 1020740..9cedf44 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -172,7 +172,6 @@ class OperatorsTest(unittest.TestCase): def test_dicts(self): # Testing dict operations... - ## self.binop_test({1:2}, {2:1}, -1, "cmp(a,b)", "__cmp__") self.binop_test({1:2,3:4}, 1, 1, "b in a", "__contains__") self.binop_test({1:2,3:4}, 2, 0, "b in a", "__contains__") self.binop_test({1:2,3:4}, 1, 2, "a[b]", "__getitem__") @@ -332,8 +331,6 @@ class OperatorsTest(unittest.TestCase): # This is an ugly hack: copy._deepcopy_dispatch[spam.spamdict] = spamdict - ## self.binop_test(spamdict({1:2}), spamdict({2:1}), -1, "cmp(a,b)", - ## "__cmp__") self.binop_test(spamdict({1:2,3:4}), 1, 1, "b in a", "__contains__") self.binop_test(spamdict({1:2,3:4}), 2, 0, "b in a", "__contains__") self.binop_test(spamdict({1:2,3:4}), 1, 2, "a[b]", "__getitem__") @@ -1004,8 +1001,8 @@ order (MRO) for bases """ # Test lookup leaks [SF bug 572567] import sys,gc class G(object): - def __cmp__(self, other): - return 0 + def __eq__(self, other): + return 1 g = G() orig_objects = len(gc.get_objects()) for i in range(10): @@ -1525,7 +1522,6 @@ order (MRO) for bases """ self.assertNotEqual(id(c1), id(c2)) hash(c1) hash(c2) - ## self.assertEqual(cmp(c1, c2), cmp(id(c1), id(c2))) self.assertEqual(c1, c1) self.assert_(c1 != c2) self.assert_(not c1 != c1) @@ -1549,7 +1545,6 @@ order (MRO) for bases """ self.assertNotEqual(id(d1), id(d2)) hash(d1) hash(d2) - ## self.assertEqual(cmp(d1, d2), cmp(id(d1), id(d2))) self.assertEqual(d1, d1) self.assertNotEqual(d1, d2) self.assert_(not d1 != d1) @@ -1610,23 +1605,6 @@ order (MRO) for bases """ self.assert_(i in p10) self.assertFalse(10 in p10) - ## # Safety test for __cmp__ - ## def unsafecmp(a, b): - ## try: - ## a.__class__.__cmp__(a, b) - ## except TypeError: - ## pass - ## else: - ## self.fail("shouldn't allow %s.__cmp__(%r, %r)" % ( - ## a.__class__, a, b)) - ## - ## unsafecmp("123", "123") - ## unsafecmp("123", "123") - ## unsafecmp(1, 1.0) - ## unsafecmp(1.0, 1) - ## unsafecmp(1, 1) - ## unsafecmp(1, 1) - def test_weakrefs(self): # Testing weak references... import weakref @@ -2538,12 +2516,16 @@ order (MRO) for bases """ c = {1: c1, 2: c2, 3: c3} for x in 1, 2, 3: for y in 1, 2, 3: - ## self.assert_(cmp(c[x], c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y)) for op in "<", "<=", "==", "!=", ">", ">=": - self.assert_(eval("c[x] %s c[y]" % op) == eval("x %s y" % op), - "x=%d, y=%d" % (x, y)) - ## self.assert_(cmp(c[x], y) == cmp(x, y), "x=%d, y=%d" % (x, y)) - ## self.assert_(cmp(x, c[y]) == cmp(x, y), "x=%d, y=%d" % (x, y)) + self.assert_(eval("c[x] %s c[y]" % op) == + eval("x %s y" % op), + "x=%d, y=%d" % (x, y)) + self.assert_(eval("c[x] %s y" % op) == + eval("x %s y" % op), + "x=%d, y=%d" % (x, y)) + self.assert_(eval("x %s c[y]" % op) == + eval("x %s y" % op), + "x=%d, y=%d" % (x, y)) def test_rich_comparisons(self): # Testing rich comparisons... diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 2e74b68..bfc31af 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -570,7 +570,7 @@ class DictTest(unittest.TestCase): self.fail("missing KeyError") def test_bad_key(self): - # Dictionary lookups should fail if __cmp__() raises an exception. + # Dictionary lookups should fail if __eq__() raises an exception. class CustomException(Exception): pass diff --git a/Lib/test/test_hash.py b/Lib/test/test_hash.py index 807c2c4..5881d03 100644 --- a/Lib/test/test_hash.py +++ b/Lib/test/test_hash.py @@ -55,13 +55,8 @@ class OnlyInequality(object): def __ne__(self, other): return self is not other -class OnlyCmp(object): - def __cmp__(self, other): - return cmp(id(self), id(other)) - class InheritedHashWithEquality(FixedHash, OnlyEquality): pass class InheritedHashWithInequality(FixedHash, OnlyInequality): pass -class InheritedHashWithCmp(FixedHash, OnlyCmp): pass class NoHash(object): __hash__ = None @@ -74,7 +69,6 @@ class HashInheritanceTestCase(unittest.TestCase): fixed_expected = [FixedHash(), InheritedHashWithEquality(), InheritedHashWithInequality(), - InheritedHashWithCmp(), ] error_expected = [NoHash(), OnlyEquality(), diff --git a/Lib/test/test_heapq.py b/Lib/test/test_heapq.py index 484ab48..e1e7e9c 100644 --- a/Lib/test/test_heapq.py +++ b/Lib/test/test_heapq.py @@ -234,9 +234,9 @@ class GetOnly: class CmpErr: "Dummy element that always raises an error during comparison" - def __cmp__(self, other): + def __eq__(self, other): raise ZeroDivisionError - __eq__ = __ne__ = __lt__ = __le__ = __gt__ = __ge__ = __cmp__ + __ne__ = __lt__ = __le__ = __gt__ = __ge__ = __eq__ def R(seqn): 'Regular generator' diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py index f7ac8ef..8dcbe7e 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py @@ -291,7 +291,7 @@ class CopyTestCase(unittest.TestCase): # Testing if the copy method created a real copy. h1 = hmac.HMAC(b"key") h2 = h1.copy() - # Using id() in case somebody has overridden __cmp__. + # Using id() in case somebody has overridden __eq__/__ne__. self.failUnless(id(h1) != id(h2), "No real copy of the HMAC instance.") self.failUnless(id(h1.inner) != id(h2.inner), "No real copy of the attribute 'inner'.") diff --git a/Lib/test/test_kqueue.py b/Lib/test/test_kqueue.py index 93deb1e..eb4865a 100644 --- a/Lib/test/test_kqueue.py +++ b/Lib/test/test_kqueue.py @@ -22,6 +22,7 @@ class TestKQueue(unittest.TestCase): self.assertRaises(ValueError, kq.fileno) def test_create_event(self): + from operator import lt, le, gt, ge fd = sys.stderr.fileno() ev = select.kevent(fd) other = select.kevent(1000) @@ -33,12 +34,12 @@ class TestKQueue(unittest.TestCase): self.assertEqual(ev.udata, 0) self.assertEqual(ev, ev) self.assertNotEqual(ev, other) - self.assertEqual(cmp(ev, other), -1) self.assert_(ev < other) self.assert_(other >= ev) - self.assertRaises(TypeError, cmp, ev, None) - self.assertRaises(TypeError, cmp, ev, 1) - self.assertRaises(TypeError, cmp, ev, "ev") + for op in lt, le, gt, ge: + self.assertRaises(TypeError, op, ev, None) + self.assertRaises(TypeError, op, ev, 1) + self.assertRaises(TypeError, op, ev, "ev") ev = select.kevent(fd, select.KQ_FILTER_WRITE) self.assertEqual(ev.ident, fd) diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index c1f8b5c..2acb3fa 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -697,7 +697,8 @@ class LongTest(unittest.TestCase): def _cmp__(self, other): if not isinstance(other, Rat): other = Rat(other) - return cmp(self.n * other.d, self.d * other.n) + x, y = self.n * other.d, self.d * other.n + return (x > y) - (x < y) def __eq__(self, other): return self._cmp__(other) == 0 def __ne__(self, other): @@ -727,8 +728,8 @@ class LongTest(unittest.TestCase): Rx = Rat(x) for y in cases: Ry = Rat(y) - Rcmp = cmp(Rx, Ry) - xycmp = cmp(x, y) + Rcmp = (Rx > Ry) - (Rx < Ry) + xycmp = (x > y) - (x < y) eq(Rcmp, xycmp, Frm("%r %r %d %d", x, y, Rcmp, xycmp)) eq(x == y, Rcmp == 0, Frm("%r == %r %d", x, y, Rcmp)) eq(x != y, Rcmp != 0, Frm("%r != %r %d", x, y, Rcmp)) diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 5a8819f..15d3c6f 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -1036,16 +1036,6 @@ class TestBinaryOps(unittest.TestCase): result = self.set ^ set([8]) self.assertEqual(result, set([2, 4, 6, 8])) - def test_cmp(self): - a, b = set('a'), set('b') - self.assertRaises(TypeError, cmp, a, b) - - # In py3k, this works! - self.assertRaises(TypeError, cmp, a, a) - - self.assertRaises(TypeError, cmp, a, 12) - self.assertRaises(TypeError, cmp, "abc", a) - #============================================================================== class TestUpdateOps(unittest.TestCase): diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py index 8b108d5..a7afe73 100644 --- a/Lib/test/test_sort.py +++ b/Lib/test/test_sort.py @@ -102,7 +102,7 @@ class TestBase(unittest.TestCase): y = x[:] y.reverse() s = x[:] - check("reversed via function", y, s, lambda a, b: cmp(b, a)) + check("reversed via function", y, s, lambda a, b: (b>a)-(b y) - (x < y) L = [1,2] self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp)) def mutating_cmp(x, y): L.append(3) del L[:] - return cmp(x, y) + return (x > y) - (x < y) self.assertRaises(ValueError, L.sort, key=CmpToKey(mutating_cmp)) memorywaster = [memorywaster] @@ -176,7 +176,10 @@ class TestDecorateSortUndecorate(unittest.TestCase): copy = data[:] random.shuffle(data) data.sort(key=str.lower) - copy.sort(key=CmpToKey(lambda x,y: cmp(x.lower(), y.lower()))) + def my_cmp(x, y): + xlower, ylower = x.lower(), y.lower() + return (xlower > ylower) - (xlower < ylower) + copy.sort(key=CmpToKey(my_cmp)) def test_baddecorator(self): data = 'The quick Brown fox Jumped over The lazy Dog'.split() @@ -246,8 +249,14 @@ class TestDecorateSortUndecorate(unittest.TestCase): data = [(random.randrange(100), i) for i in range(200)] copy1 = data[:] copy2 = data[:] - data.sort(key=CmpToKey(lambda x,y: cmp(x[0],y[0])), reverse=True) - copy1.sort(key=CmpToKey(lambda x,y: cmp(y[0],x[0]))) + def my_cmp(x, y): + x0, y0 = x[0], y[0] + return (x0 > y0) - (x0 < y0) + def my_cmp_reversed(x, y): + x0, y0 = x[0], y[0] + return (y0 > x0) - (y0 < x0) + data.sort(key=CmpToKey(my_cmp), reverse=True) + copy1.sort(key=CmpToKey(my_cmp_reversed)) self.assertEqual(data, copy1) copy2.sort(key=lambda x: x[0], reverse=True) self.assertEqual(data, copy2) diff --git a/Lib/test/test_unittest.py b/Lib/test/test_unittest.py index 9c12205..38ceb9a 100644 --- a/Lib/test/test_unittest.py +++ b/Lib/test/test_unittest.py @@ -1103,7 +1103,7 @@ class Test_TestLoader(TestCase): # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromTestCase(self): def reversed_cmp(x, y): - return -cmp(x, y) + return -((x > y) - (x < y)) class Foo(unittest.TestCase): def test_1(self): pass @@ -1119,7 +1119,7 @@ class Test_TestLoader(TestCase): # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromModule(self): def reversed_cmp(x, y): - return -cmp(x, y) + return -((x > y) - (x < y)) m = types.ModuleType('m') class Foo(unittest.TestCase): @@ -1137,7 +1137,7 @@ class Test_TestLoader(TestCase): # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromName(self): def reversed_cmp(x, y): - return -cmp(x, y) + return -((x > y) - (x < y)) m = types.ModuleType('m') class Foo(unittest.TestCase): @@ -1155,7 +1155,7 @@ class Test_TestLoader(TestCase): # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromNames(self): def reversed_cmp(x, y): - return -cmp(x, y) + return -((x > y) - (x < y)) m = types.ModuleType('m') class Foo(unittest.TestCase): @@ -1175,7 +1175,7 @@ class Test_TestLoader(TestCase): # Does it actually affect getTestCaseNames()? def test_sortTestMethodsUsing__getTestCaseNames(self): def reversed_cmp(x, y): - return -cmp(x, y) + return -((x > y) - (x < y)) class Foo(unittest.TestCase): def test_1(self): pass @@ -1188,9 +1188,19 @@ class Test_TestLoader(TestCase): self.assertEqual(loader.getTestCaseNames(Foo), test_names) # "The default value is the built-in cmp() function" + # Since cmp is now defunct, we simply verify that the results + # occur in the same order as they would with the default sort. def test_sortTestMethodsUsing__default_value(self): loader = unittest.TestLoader() - self.failUnless(loader.sortTestMethodsUsing is cmp) + + class Foo(unittest.TestCase): + def test_2(self): pass + def test_3(self): pass + def test_1(self): pass + + test_names = ['test_2', 'test_3', 'test_1'] + self.assertEqual(loader.getTestCaseNames(Foo), sorted(test_names)) + # "it can be set to None to disable the sort." # diff --git a/Lib/test/test_userdict.py b/Lib/test/test_userdict.py index 30eec71..5d4a0ff 100644 --- a/Lib/test/test_userdict.py +++ b/Lib/test/test_userdict.py @@ -47,7 +47,7 @@ class UserDictTest(mapping_tests.TestHashMappingProtocol): self.assertEqual(repr(u1), repr(d1)) self.assertEqual(repr(u2), repr(d2)) - # Test __cmp__ and __len__ + # Test rich comparison and __len__ all = [d0, d1, d2, u, u0, u1, u2, uu, uu0, uu1, uu2] for a in all: for b in all: diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py index 5a37c2f..cf9ea84 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py @@ -181,7 +181,12 @@ class TestUUID(TestCase): # Test comparison of UUIDs. for i in range(len(ascending)): for j in range(len(ascending)): - equal(cmp(i, j), cmp(ascending[i], ascending[j])) + equal(i < j, ascending[i] < ascending[j]) + equal(i <= j, ascending[i] <= ascending[j]) + equal(i == j, ascending[i] == ascending[j]) + equal(i > j, ascending[i] > ascending[j]) + equal(i >= j, ascending[i] >= ascending[j]) + equal(i != j, ascending[i] != ascending[j]) # Test sorting of UUIDs (above list is in ascending order). resorted = ascending[:] diff --git a/Lib/unittest.py b/Lib/unittest.py index fec41ca..ffb8a6c 100644 --- a/Lib/unittest.py +++ b/Lib/unittest.py @@ -539,12 +539,16 @@ def CmpToKey(mycmp): return mycmp(self.obj, other.obj) == -1 return K +def three_way_cmp(x, y): + """Return -1 if x < y, 0 if x == y and 1 if x > y""" + return (x > y) - (x < y) + class TestLoader(object): """This class is responsible for loading tests according to various criteria and returning them wrapped in a TestSuite """ testMethodPrefix = 'test' - sortTestMethodsUsing = cmp + sortTestMethodsUsing = staticmethod(three_way_cmp) suiteClass = TestSuite def loadTestsFromTestCase(self, testCaseClass): diff --git a/Lib/xml/dom/minidom.py b/Lib/xml/dom/minidom.py index 3025ed7..489ae52 100644 --- a/Lib/xml/dom/minidom.py +++ b/Lib/xml/dom/minidom.py @@ -520,11 +520,29 @@ class NamedNodeMap(object): __len__ = _get_length - def __cmp__(self, other): + def _cmp(self, other): if self._attrs is getattr(other, "_attrs", None): return 0 else: - return cmp(id(self), id(other)) + return (id(self) > id(other)) - (id(self) < id(other)) + + def __eq__(self, other): + return self._cmp(other) == 0 + + def __ge__(self, other): + return self._cmp(other) >= 0 + + def __gt__(self, other): + return self._cmp(other) > 0 + + def __le__(self, other): + return self._cmp(other) <= 0 + + def __lt__(self, other): + return self._cmp(other) < 0 + + def __ne__(self, other): + return self._cmp(other) != 0 def __getitem__(self, attname_or_tuple): if isinstance(attname_or_tuple, tuple): diff --git a/Lib/xml/etree/ElementTree.py b/Lib/xml/etree/ElementTree.py index 782af81..cfac4f7 100644 --- a/Lib/xml/etree/ElementTree.py +++ b/Lib/xml/etree/ElementTree.py @@ -498,10 +498,30 @@ class QName: return self.text def __hash__(self): return hash(self.text) - def __cmp__(self, other): + def __le__(self, other): if isinstance(other, QName): - return cmp(self.text, other.text) - return cmp(self.text, other) + return self.text <= other.text + return self.text <= other + def __lt__(self, other): + if isinstance(other, QName): + return self.text < other.text + return self.text < other + def __ge__(self, other): + if isinstance(other, QName): + return self.text >= other.text + return self.text >= other + def __gt__(self, other): + if isinstance(other, QName): + return self.text > other.text + return self.text > other + def __eq__(self, other): + if isinstance(other, QName): + return self.text == other.text + return self.text == other + def __ne__(self, other): + if isinstance(other, QName): + return self.text != other.text + return self.text != other ## # ElementTree wrapper class. This class represents an entire element diff --git a/Lib/xmlrpc/client.py b/Lib/xmlrpc/client.py index d18efce..c752621 100644 --- a/Lib/xmlrpc/client.py +++ b/Lib/xmlrpc/client.py @@ -349,10 +349,6 @@ class DateTime: def timetuple(self): return time.strptime(self.value, "%Y%m%dT%H:%M:%S") - def __cmp__(self, other): - s, o = self.make_comparable(other) - return cmp(s, o) - ## # Get date/time value. # diff --git a/Tools/unicode/makeunicodedata.py b/Tools/unicode/makeunicodedata.py index 0b32412..835e98b 100644 --- a/Tools/unicode/makeunicodedata.py +++ b/Tools/unicode/makeunicodedata.py @@ -457,15 +457,6 @@ def makeunicodetype(unicode, trace): # -------------------------------------------------------------------- # unicode name database -def CmpToKey(mycmp): - 'Convert a cmp= function into a key= function' - class K(object): - def __init__(self, obj, *args): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) == -1 - return K - def makeunicodename(unicode, trace): FILE = "Modules/unicodename_db.h" @@ -508,14 +499,10 @@ def makeunicodename(unicode, trace): wordlist = list(words.items()) # sort on falling frequency, then by name - def cmpwords(a,b): + def word_key(a): aword, alist = a - bword, blist = b - r = -cmp(len(alist),len(blist)) - if r: - return r - return cmp(aword, bword) - wordlist.sort(key=CmpToKey(cmpwords)) + return -len(alist), aword + wordlist.sort(key=word_key) # figure out how many phrasebook escapes we need escapes = 0 -- cgit v0.12