Index: PCbuild/rt.bat =================================================================== --- PCbuild/rt.bat (revision 62272) +++ PCbuild/rt.bat (working copy) @@ -39,7 +39,7 @@ if "%1"=="-x64" (set prefix=amd64) & (set tcltk=tcltk64) & shift & goto CheckOpts PATH %PATH%;..\..\%tcltk%\bin -set exe=%prefix%\python%suffix% +set exe=%prefix%\python%suffix% -3 set cmd=%exe% %dashO% -E -tt ../lib/test/regrtest.py %1 %2 %3 %4 %5 %6 %7 %8 %9 if defined qmode goto Qmode Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 62272) +++ Objects/typeobject.c (working copy) @@ -3633,27 +3633,6 @@ type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; } -static char *hash_name_op[] = { - "__eq__", - "__cmp__", - "__hash__", - NULL -}; - -static int -overrides_hash(PyTypeObject *type) -{ - char **p; - PyObject *dict = type->tp_dict; - - assert(dict != NULL); - for (p = hash_name_op; *p; p++) { - if (PyDict_GetItemString(dict, *p) != NULL) - return 1; - } - return 0; -} - static void inherit_slots(PyTypeObject *type, PyTypeObject *base) { @@ -3787,8 +3766,7 @@ if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) { if (type->tp_compare == NULL && type->tp_richcompare == NULL && - type->tp_hash == NULL && - !overrides_hash(type)) + type->tp_hash == NULL) { type->tp_compare = base->tp_compare; type->tp_richcompare = base->tp_richcompare; @@ -5243,6 +5221,24 @@ static PyObject *hash_str, *eq_str, *cmp_str; long h; + if (Py_Py3kWarningFlag && + PyDict_GetItemString(Py_TYPE(self)->tp_dict, "__hash__") == NULL) { + if (PyDict_GetItemString(Py_TYPE(self)->tp_dict, + "__eq__") != NULL) { + if (PyErr_Warn(PyExc_DeprecationWarning, + "type defines __eq__ but not __hash__, " + "and will not be hashable in 3.x") < 0) + return -1; + } + else if (PyDict_GetItemString(Py_TYPE(self)->tp_dict, + "__cmp__") != NULL) { + if (PyErr_Warn(PyExc_DeprecationWarning, + "type defines __cmp__ but not __hash__, " + "and will not be hashable in 3.x") < 0) + return -1; + } + } + func = lookup_method(self, "__hash__", &hash_str); if (func != NULL && func != Py_None) { @@ -5834,6 +5830,8 @@ "x.__cmp__(y) <==> cmp(x,y)"), TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, "x.__hash__() <==> hash(x)"), + TPSLOT("__eq__", tp_hash, NULL, NULL, ""), + TPSLOT("__cmp__", tp_hash, NULL, NULL, ""), FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS), TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, Index: Lib/test/test_dict.py =================================================================== --- Lib/test/test_dict.py (revision 62272) +++ Lib/test/test_dict.py (working copy) @@ -97,8 +97,6 @@ class BadEq(object): def __eq__(self, other): raise Exc() - def __hash__(self): - return 24 d = {} d[BadEq()] = 42 @@ -402,8 +400,6 @@ class BadCmp(object): def __eq__(self, other): raise Exc() - def __hash__(self): - return 42 d1 = {BadCmp(): 1} d2 = {1: 1} Index: Lib/test/test_py3kwarn.py =================================================================== --- Lib/test/test_py3kwarn.py (revision 62272) +++ Lib/test/test_py3kwarn.py (working copy) @@ -94,6 +94,21 @@ with catch_warning() as w: self.assertWarning(sorted(lst, cmp), w, expected) + def test_hash_inheritance(self): + expected = "type defines %s but not __hash__, " \ + "and will not be hashable in 3.x" + with catch_warning() as w: + class C(object): + def __eq__(self, other): + return False + self.assertWarning(hash(C()), w, expected % '__eq__') + + with catch_warning() as w: + class C(object): + def __cmp__(self, other): + return False + self.assertWarning(hash(C()), w, expected % '__cmp__') + def test_sys_exc_clear(self): expected = 'sys.exc_clear() not supported in 3.x; use except clauses' with catch_warning() as w: Index: Lib/test/mapping_tests.py =================================================================== --- Lib/test/mapping_tests.py (revision 62272) +++ Lib/test/mapping_tests.py (working copy) @@ -557,8 +557,6 @@ class BadEq(object): def __eq__(self, other): raise Exc() - def __hash__(self): - return 24 d = self._empty_mapping() d[BadEq()] = 42 @@ -644,8 +642,6 @@ class BadCmp(object): def __eq__(self, other): raise Exc() - def __hash__(self): - return 42 d1 = self._full_mapping({BadCmp(): 1}) d2 = self._full_mapping({1: 1}) Index: Lib/test/test_richcmp.py =================================================================== --- Lib/test/test_richcmp.py (revision 62272) +++ Lib/test/test_richcmp.py (working copy) @@ -86,34 +86,6 @@ return other -class SimpleOrder(object): - """ - A simple class that defines order but not full comparison. - """ - - def __init__(self, value): - self.value = value - - def __lt__(self, other): - if not isinstance(other, SimpleOrder): - return True - return self.value < other.value - - def __gt__(self, other): - if not isinstance(other, SimpleOrder): - return False - return self.value > other.value - - -class DumbEqualityWithoutHash(object): - """ - A class that define __eq__, but no __hash__: it shouldn't be hashable. - """ - - def __eq__(self, other): - return False - - opmap = { "lt": (lambda a,b: a< b, operator.lt, operator.__lt__), "le": (lambda a,b: a<=b, operator.le, operator.__le__), @@ -360,38 +332,8 @@ self.assertIs(op(x, y), True) -class HashableTest(unittest.TestCase): - """ - Test hashability of classes with rich operators defined. - """ - - def test_simpleOrderHashable(self): - """ - A class that only defines __gt__ and/or __lt__ should be hashable. - """ - a = SimpleOrder(1) - b = SimpleOrder(2) - self.assert_(a < b) - self.assert_(b > a) - self.assert_(a.__hash__ is not None) - - def test_notHashableException(self): - """ - If a class is not hashable, it should raise a TypeError with an - understandable message. - """ - a = DumbEqualityWithoutHash() - try: - hash(a) - except TypeError, e: - self.assertEquals(str(e), - "unhashable type: 'DumbEqualityWithoutHash'") - else: - raise test_support.TestFailed("Should not be here") - - def test_main(): - test_support.run_unittest(VectorTest, NumberTest, MiscTest, DictTest, ListTest, HashableTest) + test_support.run_unittest(VectorTest, NumberTest, MiscTest, DictTest, ListTest) if __name__ == "__main__": test_main()