Issue 2235: Py3k warnings are now emitted for classes that will no longer inherit a__hash__ implementation from a parent class in Python 3.x. The standard library and test suite have been updated to not emit these warnings.
This commit is contained in:
parent
f8d62d23e9
commit
48361f5cbf
|
@ -25,6 +25,7 @@ class UserList(collections.MutableSequence):
|
||||||
else: return other
|
else: return other
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.data, self.__cast(other))
|
return cmp(self.data, self.__cast(other))
|
||||||
|
__hash__ = None # Mutable sequence, so not hashable
|
||||||
def __contains__(self, item): return item in self.data
|
def __contains__(self, item): return item in self.data
|
||||||
def __len__(self): return len(self.data)
|
def __len__(self): return len(self.data)
|
||||||
def __getitem__(self, i): return self.data[i]
|
def __getitem__(self, i): return self.data[i]
|
||||||
|
|
|
@ -207,6 +207,9 @@ class Set(Sized, Iterable, Container):
|
||||||
other = self._from_iterable(other)
|
other = self._from_iterable(other)
|
||||||
return (self - other) | (other - self)
|
return (self - other) | (other - self)
|
||||||
|
|
||||||
|
# Sets are not hashable by default, but subclasses can change this
|
||||||
|
__hash__ = None
|
||||||
|
|
||||||
def _hash(self):
|
def _hash(self):
|
||||||
"""Compute the hash value of a set.
|
"""Compute the hash value of a set.
|
||||||
|
|
||||||
|
@ -350,6 +353,9 @@ class Mapping(Sized, Iterable, Container):
|
||||||
def values(self):
|
def values(self):
|
||||||
return [self[key] for key in self]
|
return [self[key] for key in self]
|
||||||
|
|
||||||
|
# Mappings are not hashable by default, but subclasses can change this
|
||||||
|
__hash__ = None
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return isinstance(other, Mapping) and \
|
return isinstance(other, Mapping) and \
|
||||||
dict(self.items()) == dict(other.items())
|
dict(self.items()) == dict(other.items())
|
||||||
|
|
|
@ -6,6 +6,8 @@ class MyInt(c_int):
|
||||||
if type(other) != MyInt:
|
if type(other) != MyInt:
|
||||||
return -1
|
return -1
|
||||||
return cmp(self.value, other.value)
|
return cmp(self.value, other.value)
|
||||||
|
def __hash__(self): # Silence Py3k warning
|
||||||
|
return hash(self.value)
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@ class Number(object):
|
||||||
"""
|
"""
|
||||||
__metaclass__ = ABCMeta
|
__metaclass__ = ABCMeta
|
||||||
|
|
||||||
|
# Concrete numeric types must provide their own hash implementation
|
||||||
|
__hash__ = None
|
||||||
|
|
||||||
|
|
||||||
## Notes on Decimal
|
## Notes on Decimal
|
||||||
## ----------------
|
## ----------------
|
||||||
|
|
|
@ -1064,6 +1064,7 @@ class BuiltinTest(unittest.TestCase):
|
||||||
class badzero(int):
|
class badzero(int):
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
__hash__ = None # Invalid cmp makes this unhashable
|
||||||
self.assertRaises(RuntimeError, range, a, a + 1, badzero(1))
|
self.assertRaises(RuntimeError, range, a, a + 1, badzero(1))
|
||||||
|
|
||||||
# Reject floats when it would require PyLongs to represent.
|
# Reject floats when it would require PyLongs to represent.
|
||||||
|
|
|
@ -309,6 +309,7 @@ class CoercionTest(unittest.TestCase):
|
||||||
def __cmp__(slf, other):
|
def __cmp__(slf, other):
|
||||||
self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
|
self.assert_(other == 42, 'expected evil_coercer, got %r' % other)
|
||||||
return 0
|
return 0
|
||||||
|
__hash__ = None # Invalid cmp makes this unhashable
|
||||||
self.assertEquals(cmp(WackyComparer(), evil_coercer), 0)
|
self.assertEquals(cmp(WackyComparer(), evil_coercer), 0)
|
||||||
# ...and classic classes too, since that code path is a little different
|
# ...and classic classes too, since that code path is a little different
|
||||||
class ClassicWackyComparer:
|
class ClassicWackyComparer:
|
||||||
|
|
|
@ -172,6 +172,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
|
||||||
class H(Hashable):
|
class H(Hashable):
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return super(H, self).__hash__()
|
return super(H, self).__hash__()
|
||||||
|
__eq__ = Hashable.__eq__ # Silence Py3k warning
|
||||||
self.assertEqual(hash(H()), 0)
|
self.assertEqual(hash(H()), 0)
|
||||||
self.failIf(issubclass(int, H))
|
self.failIf(issubclass(int, H))
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,7 @@ class TestCopy(unittest.TestCase):
|
||||||
return (C, (), self.__dict__)
|
return (C, (), self.__dict__)
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.__dict__, other.__dict__)
|
return cmp(self.__dict__, other.__dict__)
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
x = C()
|
x = C()
|
||||||
x.foo = [42]
|
x.foo = [42]
|
||||||
y = copy.copy(x)
|
y = copy.copy(x)
|
||||||
|
@ -451,6 +452,7 @@ class TestCopy(unittest.TestCase):
|
||||||
self.__dict__.update(state)
|
self.__dict__.update(state)
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.__dict__, other.__dict__)
|
return cmp(self.__dict__, other.__dict__)
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
x = C()
|
x = C()
|
||||||
x.foo = [42]
|
x.foo = [42]
|
||||||
y = copy.copy(x)
|
y = copy.copy(x)
|
||||||
|
@ -477,6 +479,7 @@ class TestCopy(unittest.TestCase):
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return (cmp(list(self), list(other)) or
|
return (cmp(list(self), list(other)) or
|
||||||
cmp(self.__dict__, other.__dict__))
|
cmp(self.__dict__, other.__dict__))
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
x = C([[1, 2], 3])
|
x = C([[1, 2], 3])
|
||||||
y = copy.copy(x)
|
y = copy.copy(x)
|
||||||
self.assertEqual(x, y)
|
self.assertEqual(x, y)
|
||||||
|
@ -494,6 +497,7 @@ class TestCopy(unittest.TestCase):
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return (cmp(dict(self), list(dict)) or
|
return (cmp(dict(self), list(dict)) or
|
||||||
cmp(self.__dict__, other.__dict__))
|
cmp(self.__dict__, other.__dict__))
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
x = C([("foo", [1, 2]), ("bar", 3)])
|
x = C([("foo", [1, 2]), ("bar", 3)])
|
||||||
y = copy.copy(x)
|
y = copy.copy(x)
|
||||||
self.assertEqual(x, y)
|
self.assertEqual(x, y)
|
||||||
|
|
|
@ -986,6 +986,7 @@ class TestDate(HarmlessMixedComparison, unittest.TestCase):
|
||||||
# compare-by-address (which never says "equal" for distinct
|
# compare-by-address (which never says "equal" for distinct
|
||||||
# objects).
|
# objects).
|
||||||
return 0
|
return 0
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
|
|
||||||
# This still errors, because date and datetime comparison raise
|
# This still errors, because date and datetime comparison raise
|
||||||
# TypeError instead of NotImplemented when they don't know what to
|
# TypeError instead of NotImplemented when they don't know what to
|
||||||
|
|
|
@ -1121,6 +1121,7 @@ order (MRO) for bases """
|
||||||
class G(object):
|
class G(object):
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return 0
|
return 0
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
g = G()
|
g = G()
|
||||||
orig_objects = len(gc.get_objects())
|
orig_objects = len(gc.get_objects())
|
||||||
for i in xrange(10):
|
for i in xrange(10):
|
||||||
|
@ -2727,6 +2728,7 @@ order (MRO) for bases """
|
||||||
if isinstance(other, int) or isinstance(other, long):
|
if isinstance(other, int) or isinstance(other, long):
|
||||||
return cmp(self.value, other)
|
return cmp(self.value, other)
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
|
|
||||||
c1 = C(1)
|
c1 = C(1)
|
||||||
c2 = C(2)
|
c2 = C(2)
|
||||||
|
@ -2755,6 +2757,7 @@ order (MRO) for bases """
|
||||||
return abs(self - other) <= 1e-6
|
return abs(self - other) <= 1e-6
|
||||||
except:
|
except:
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
zz = ZZ(1.0000003)
|
zz = ZZ(1.0000003)
|
||||||
self.assertEqual(zz, 1+0j)
|
self.assertEqual(zz, 1+0j)
|
||||||
self.assertEqual(1+0j, zz)
|
self.assertEqual(1+0j, zz)
|
||||||
|
@ -2767,6 +2770,7 @@ order (MRO) for bases """
|
||||||
self.value = int(value)
|
self.value = int(value)
|
||||||
def __cmp__(self_, other):
|
def __cmp__(self_, other):
|
||||||
self.fail("shouldn't call __cmp__")
|
self.fail("shouldn't call __cmp__")
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if isinstance(other, C):
|
if isinstance(other, C):
|
||||||
return self.value == other.value
|
return self.value == other.value
|
||||||
|
@ -3262,6 +3266,7 @@ order (MRO) for bases """
|
||||||
class S(str):
|
class S(str):
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.lower() == other.lower()
|
return self.lower() == other.lower()
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
|
|
||||||
def test_subclass_propagation(self):
|
def test_subclass_propagation(self):
|
||||||
# Testing propagation of slot functions to subclasses...
|
# Testing propagation of slot functions to subclasses...
|
||||||
|
|
|
@ -52,6 +52,9 @@ class FixedHash(object):
|
||||||
class OnlyEquality(object):
|
class OnlyEquality(object):
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self is other
|
return self is other
|
||||||
|
# Trick to suppress Py3k warning in 2.x
|
||||||
|
__hash__ = None
|
||||||
|
del OnlyEquality.__hash__
|
||||||
|
|
||||||
class OnlyInequality(object):
|
class OnlyInequality(object):
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
|
@ -60,6 +63,9 @@ class OnlyInequality(object):
|
||||||
class OnlyCmp(object):
|
class OnlyCmp(object):
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(id(self), id(other))
|
return cmp(id(self), id(other))
|
||||||
|
# Trick to suppress Py3k warning in 2.x
|
||||||
|
__hash__ = None
|
||||||
|
del OnlyCmp.__hash__
|
||||||
|
|
||||||
class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
|
class InheritedHashWithEquality(FixedHash, OnlyEquality): pass
|
||||||
class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
|
class InheritedHashWithInequality(FixedHash, OnlyInequality): pass
|
||||||
|
@ -71,18 +77,15 @@ class NoHash(object):
|
||||||
class HashInheritanceTestCase(unittest.TestCase):
|
class HashInheritanceTestCase(unittest.TestCase):
|
||||||
default_expected = [object(),
|
default_expected = [object(),
|
||||||
DefaultHash(),
|
DefaultHash(),
|
||||||
|
OnlyEquality(),
|
||||||
|
OnlyInequality(),
|
||||||
|
OnlyCmp(),
|
||||||
]
|
]
|
||||||
fixed_expected = [FixedHash(),
|
fixed_expected = [FixedHash(),
|
||||||
InheritedHashWithEquality(),
|
InheritedHashWithEquality(),
|
||||||
InheritedHashWithInequality(),
|
InheritedHashWithInequality(),
|
||||||
InheritedHashWithCmp(),
|
InheritedHashWithCmp(),
|
||||||
]
|
]
|
||||||
# TODO: Change these to expecting an exception
|
|
||||||
# when forward porting to Py3k
|
|
||||||
warning_expected = [OnlyEquality(),
|
|
||||||
OnlyInequality(),
|
|
||||||
OnlyCmp(),
|
|
||||||
]
|
|
||||||
error_expected = [NoHash()]
|
error_expected = [NoHash()]
|
||||||
|
|
||||||
def test_default_hash(self):
|
def test_default_hash(self):
|
||||||
|
@ -93,20 +96,13 @@ class HashInheritanceTestCase(unittest.TestCase):
|
||||||
for obj in self.fixed_expected:
|
for obj in self.fixed_expected:
|
||||||
self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
|
self.assertEqual(hash(obj), _FIXED_HASH_VALUE)
|
||||||
|
|
||||||
def test_warning_hash(self):
|
|
||||||
for obj in self.warning_expected:
|
|
||||||
# TODO: Check for the expected Py3k warning here
|
|
||||||
obj_hash = hash(obj)
|
|
||||||
self.assertEqual(obj_hash, _default_hash(obj))
|
|
||||||
|
|
||||||
def test_error_hash(self):
|
def test_error_hash(self):
|
||||||
for obj in self.error_expected:
|
for obj in self.error_expected:
|
||||||
self.assertRaises(TypeError, hash, obj)
|
self.assertRaises(TypeError, hash, obj)
|
||||||
|
|
||||||
def test_hashable(self):
|
def test_hashable(self):
|
||||||
objects = (self.default_expected +
|
objects = (self.default_expected +
|
||||||
self.fixed_expected +
|
self.fixed_expected)
|
||||||
self.warning_expected)
|
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
self.assert_(isinstance(obj, Hashable), repr(obj))
|
self.assert_(isinstance(obj, Hashable), repr(obj))
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ class OperatorTestCase(unittest.TestCase):
|
||||||
class C(object):
|
class C(object):
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
raise SyntaxError
|
raise SyntaxError
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
self.failUnlessRaises(TypeError, operator.eq)
|
self.failUnlessRaises(TypeError, operator.eq)
|
||||||
self.failUnlessRaises(SyntaxError, operator.eq, C(), C())
|
self.failUnlessRaises(SyntaxError, operator.eq, C(), C())
|
||||||
self.failIf(operator.eq(1, 0))
|
self.failIf(operator.eq(1, 0))
|
||||||
|
|
|
@ -12,6 +12,9 @@ if not sys.py3kwarning:
|
||||||
|
|
||||||
class TestPy3KWarnings(unittest.TestCase):
|
class TestPy3KWarnings(unittest.TestCase):
|
||||||
|
|
||||||
|
def assertWarning(self, _, warning, expected_message):
|
||||||
|
self.assertEqual(str(warning.message), expected_message)
|
||||||
|
|
||||||
def test_backquote(self):
|
def test_backquote(self):
|
||||||
expected = 'backquote not supported in 3.x; use repr()'
|
expected = 'backquote not supported in 3.x; use repr()'
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
|
@ -28,30 +31,41 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
safe_exec("True = False")
|
safe_exec("True = False")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("False = True")
|
safe_exec("False = True")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
try:
|
try:
|
||||||
safe_exec("obj.False = True")
|
safe_exec("obj.False = True")
|
||||||
except NameError: pass
|
except NameError: pass
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
try:
|
try:
|
||||||
safe_exec("obj.True = False")
|
safe_exec("obj.True = False")
|
||||||
except NameError: pass
|
except NameError: pass
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("def False(): pass")
|
safe_exec("def False(): pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("def True(): pass")
|
safe_exec("def True(): pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("class False: pass")
|
safe_exec("class False: pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("class True: pass")
|
safe_exec("class True: pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("def f(True=43): pass")
|
safe_exec("def f(True=43): pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("def f(False=None): pass")
|
safe_exec("def f(False=None): pass")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("f(False=True)")
|
safe_exec("f(False=True)")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
w.reset()
|
||||||
safe_exec("f(True=1)")
|
safe_exec("f(True=1)")
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
|
||||||
|
@ -60,20 +74,25 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
expected = 'type inequality comparisons not supported in 3.x'
|
expected = 'type inequality comparisons not supported in 3.x'
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(int < str, w, expected)
|
self.assertWarning(int < str, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(type < object, w, expected)
|
self.assertWarning(type < object, w, expected)
|
||||||
|
|
||||||
def test_object_inequality_comparisons(self):
|
def test_object_inequality_comparisons(self):
|
||||||
expected = 'comparing unequal types not supported in 3.x'
|
expected = 'comparing unequal types not supported in 3.x'
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(str < [], w, expected)
|
self.assertWarning(str < [], w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(object() < (1, 2), w, expected)
|
self.assertWarning(object() < (1, 2), w, expected)
|
||||||
|
|
||||||
def test_dict_inequality_comparisons(self):
|
def test_dict_inequality_comparisons(self):
|
||||||
expected = 'dict inequality comparisons not supported in 3.x'
|
expected = 'dict inequality comparisons not supported in 3.x'
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning({} < {2:3}, w, expected)
|
self.assertWarning({} < {2:3}, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning({} <= {}, w, expected)
|
self.assertWarning({} <= {}, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning({} > {2:3}, w, expected)
|
self.assertWarning({} > {2:3}, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning({2:3} >= {}, w, expected)
|
self.assertWarning({2:3} >= {}, w, expected)
|
||||||
|
|
||||||
def test_cell_inequality_comparisons(self):
|
def test_cell_inequality_comparisons(self):
|
||||||
|
@ -86,6 +105,7 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
cell1, = f(1).func_closure
|
cell1, = f(1).func_closure
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(cell0 == cell1, w, expected)
|
self.assertWarning(cell0 == cell1, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(cell0 < cell1, w, expected)
|
self.assertWarning(cell0 < cell1, w, expected)
|
||||||
|
|
||||||
def test_code_inequality_comparisons(self):
|
def test_code_inequality_comparisons(self):
|
||||||
|
@ -96,8 +116,11 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(f.func_code < g.func_code, w, expected)
|
self.assertWarning(f.func_code < g.func_code, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(f.func_code <= g.func_code, w, expected)
|
self.assertWarning(f.func_code <= g.func_code, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(f.func_code >= g.func_code, w, expected)
|
self.assertWarning(f.func_code >= g.func_code, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(f.func_code > g.func_code, w, expected)
|
self.assertWarning(f.func_code > g.func_code, w, expected)
|
||||||
|
|
||||||
def test_builtin_function_or_method_comparisons(self):
|
def test_builtin_function_or_method_comparisons(self):
|
||||||
|
@ -107,13 +130,13 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
meth = {}.get
|
meth = {}.get
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(func < meth, w, expected)
|
self.assertWarning(func < meth, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(func > meth, w, expected)
|
self.assertWarning(func > meth, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(meth <= func, w, expected)
|
self.assertWarning(meth <= func, w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(meth >= func, w, expected)
|
self.assertWarning(meth >= func, w, expected)
|
||||||
|
|
||||||
def assertWarning(self, _, warning, expected_message):
|
|
||||||
self.assertEqual(str(warning.message), expected_message)
|
|
||||||
|
|
||||||
def test_sort_cmp_arg(self):
|
def test_sort_cmp_arg(self):
|
||||||
expected = "the cmp argument is not supported in 3.x"
|
expected = "the cmp argument is not supported in 3.x"
|
||||||
lst = range(5)
|
lst = range(5)
|
||||||
|
@ -121,8 +144,11 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
|
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(lst.sort(cmp=cmp), w, expected)
|
self.assertWarning(lst.sort(cmp=cmp), w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(sorted(lst, cmp=cmp), w, expected)
|
self.assertWarning(sorted(lst, cmp=cmp), w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(lst.sort(cmp), w, expected)
|
self.assertWarning(lst.sort(cmp), w, expected)
|
||||||
|
w.reset()
|
||||||
self.assertWarning(sorted(lst, cmp), w, expected)
|
self.assertWarning(sorted(lst, cmp), w, expected)
|
||||||
|
|
||||||
def test_sys_exc_clear(self):
|
def test_sys_exc_clear(self):
|
||||||
|
@ -156,7 +182,7 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
self.assertWarning(None, w, expected)
|
self.assertWarning(None, w, expected)
|
||||||
|
|
||||||
def test_buffer(self):
|
def test_buffer(self):
|
||||||
expected = 'buffer() not supported in 3.x; use memoryview()'
|
expected = 'buffer() not supported in 3.x'
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(buffer('a'), w, expected)
|
self.assertWarning(buffer('a'), w, expected)
|
||||||
|
|
||||||
|
@ -167,6 +193,64 @@ class TestPy3KWarnings(unittest.TestCase):
|
||||||
with catch_warning() as w:
|
with catch_warning() as w:
|
||||||
self.assertWarning(f.xreadlines(), w, expected)
|
self.assertWarning(f.xreadlines(), w, expected)
|
||||||
|
|
||||||
|
def test_hash_inheritance(self):
|
||||||
|
with catch_warning() as w:
|
||||||
|
# With object as the base class
|
||||||
|
class WarnOnlyCmp(object):
|
||||||
|
def __cmp__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 1)
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class WarnOnlyEq(object):
|
||||||
|
def __eq__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 1)
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __eq__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class WarnCmpAndEq(object):
|
||||||
|
def __cmp__(self, other): pass
|
||||||
|
def __eq__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 2)
|
||||||
|
self.assertWarning(None, w.warnings[-2],
|
||||||
|
"Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __eq__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class NoWarningOnlyHash(object):
|
||||||
|
def __hash__(self): pass
|
||||||
|
self.assertEqual(len(w.warnings), 0)
|
||||||
|
# With an intermediate class in the heirarchy
|
||||||
|
class DefinesAllThree(object):
|
||||||
|
def __cmp__(self, other): pass
|
||||||
|
def __eq__(self, other): pass
|
||||||
|
def __hash__(self): pass
|
||||||
|
class WarnOnlyCmp(DefinesAllThree):
|
||||||
|
def __cmp__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 1)
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class WarnOnlyEq(DefinesAllThree):
|
||||||
|
def __eq__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 1)
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __eq__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class WarnCmpAndEq(DefinesAllThree):
|
||||||
|
def __cmp__(self, other): pass
|
||||||
|
def __eq__(self, other): pass
|
||||||
|
self.assertEqual(len(w.warnings), 2)
|
||||||
|
self.assertWarning(None, w.warnings[-2],
|
||||||
|
"Overriding __cmp__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
self.assertWarning(None, w,
|
||||||
|
"Overriding __eq__ blocks inheritance of __hash__ in 3.x")
|
||||||
|
w.reset()
|
||||||
|
class NoWarningOnlyHash(DefinesAllThree):
|
||||||
|
def __hash__(self): pass
|
||||||
|
self.assertEqual(len(w.warnings), 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestStdlibRemovals(unittest.TestCase):
|
class TestStdlibRemovals(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ class SliceTest(unittest.TestCase):
|
||||||
class BadCmp(object):
|
class BadCmp(object):
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
raise Exc
|
raise Exc
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
|
|
||||||
s1 = slice(BadCmp())
|
s1 = slice(BadCmp())
|
||||||
s2 = slice(BadCmp())
|
s2 = slice(BadCmp())
|
||||||
|
|
|
@ -70,6 +70,7 @@ class TestBase(unittest.TestCase):
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self.key, other.key)
|
return cmp(self.key, other.key)
|
||||||
|
__hash__ = None # Silence Py3k warning
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Stable(%d, %d)" % (self.key, self.index)
|
return "Stable(%d, %d)" % (self.key, self.index)
|
||||||
|
|
|
@ -425,6 +425,9 @@ class TestSuite:
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self == other
|
return not self == other
|
||||||
|
|
||||||
|
# Can't guarantee hash invariant, so flag as unhashable
|
||||||
|
__hash__ = None
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self._tests)
|
return iter(self._tests)
|
||||||
|
|
||||||
|
|
|
@ -516,6 +516,7 @@ class NamedNodeMap(object):
|
||||||
|
|
||||||
__len__ = _get_length
|
__len__ = _get_length
|
||||||
|
|
||||||
|
__hash__ = None # Mutable type can't be correctly hashed
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
if self._attrs is getattr(other, "_attrs", None):
|
if self._attrs is getattr(other, "_attrs", None):
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -3648,6 +3648,22 @@ inherit_special(PyTypeObject *type, PyTypeObject *base)
|
||||||
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
|
type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
overrides_name(PyTypeObject *type, char *name)
|
||||||
|
{
|
||||||
|
PyObject *dict = type->tp_dict;
|
||||||
|
|
||||||
|
assert(dict != NULL);
|
||||||
|
if (PyDict_GetItemString(dict, name) != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OVERRIDES_HASH(x) overrides_name(x, "__hash__")
|
||||||
|
#define OVERRIDES_CMP(x) overrides_name(x, "__cmp__")
|
||||||
|
#define OVERRIDES_EQ(x) overrides_name(x, "__eq__")
|
||||||
|
|
||||||
static void
|
static void
|
||||||
inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
||||||
{
|
{
|
||||||
|
@ -3786,6 +3802,25 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
|
||||||
type->tp_compare = base->tp_compare;
|
type->tp_compare = base->tp_compare;
|
||||||
type->tp_richcompare = base->tp_richcompare;
|
type->tp_richcompare = base->tp_richcompare;
|
||||||
type->tp_hash = base->tp_hash;
|
type->tp_hash = base->tp_hash;
|
||||||
|
/* Check for changes to inherited methods in Py3k*/
|
||||||
|
if (Py_Py3kWarningFlag) {
|
||||||
|
if (base->tp_hash &&
|
||||||
|
(base->tp_hash != PyObject_HashNotImplemented) &&
|
||||||
|
!OVERRIDES_HASH(type)) {
|
||||||
|
if (OVERRIDES_CMP(type)) {
|
||||||
|
PyErr_WarnPy3k("Overriding "
|
||||||
|
"__cmp__ blocks inheritance "
|
||||||
|
"of __hash__ in 3.x",
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
if (OVERRIDES_EQ(type)) {
|
||||||
|
PyErr_WarnPy3k("Overriding "
|
||||||
|
"__eq__ blocks inheritance "
|
||||||
|
"of __hash__ in 3.x",
|
||||||
|
1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
Loading…
Reference in New Issue