[Python-3000-checkins] r51454 - in python/branches/p3yk: BROKEN Include/object.h Lib/test/mapping_tests.py Lib/test/test_dict.py Objects/object.c Objects/typeobject.c

guido.van.rossum python-3000-checkins at python.org
Tue Aug 22 01:36:27 CEST 2006


Author: guido.van.rossum
Date: Tue Aug 22 01:36:26 2006
New Revision: 51454

Modified:
   python/branches/p3yk/BROKEN
   python/branches/p3yk/Include/object.h
   python/branches/p3yk/Lib/test/mapping_tests.py
   python/branches/p3yk/Lib/test/test_dict.py
   python/branches/p3yk/Objects/object.c
   python/branches/p3yk/Objects/typeobject.c
Log:
Change the way __hash__ is inherited; when __eq__ or __cmp__ is overridden
but __hash__ is not, set __hash__ explicitly to None (and tp_hash to NULL).
All unit tests pass now!


Modified: python/branches/p3yk/BROKEN
==============================================================================
--- python/branches/p3yk/BROKEN	(original)
+++ python/branches/p3yk/BROKEN	Tue Aug 22 01:36:26 2006
@@ -1,60 +1 @@
-////////////////////////////////////////////////////////////////////////
-test_class
-////////////////////////////////////////////////////////////////////////
-
-test test_class failed -- hash(C1()) should raise <class 'exceptions.TypeError'>
-Also hash(C2())
-Also stack blowout, recursing between
-#5921 0x0003868c in slot_tp_call (self=0x5b0c90, args=0x338030, kwds=0x0) at ../Objects/typeobject.c:4583
-#5922 0x00021124 in PyObject_Call (func=0x5b0c90, arg=0x3384c0, kw=0x134e10) at ../Objects/abstract.c:1791
-
-////////////////////////////////////////////////////////////////////////
-test_descr
-////////////////////////////////////////////////////////////////////////
-
-Testing hash of mutable subclasses...
-Traceback (most recent call last):
-  File "../Lib/test/test_descr.py", line 4096, in <module>
-    test_main()
-  File "../Lib/test/test_descr.py", line 4059, in test_main
-    hashinherit()
-  File "../Lib/test/test_descr.py", line 3108, in hashinherit
-    raise TestFailed, "hash() of dict subclass should fail"
-test.test_support.TestFailed: hash() of dict subclass should fail
-
-
-////////////////////////////////////////////////////////////////////////
-test_set
-////////////////////////////////////////////////////////////////////////
-
-======================================================================
-FAIL: test_contains (__main__.TestSetSubclass)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "../Lib/test/test_set.py", line 52, in test_contains
-    self.assert_(self.thetype(self.letters) in s)
-AssertionError
-
-======================================================================
-FAIL: test_discard (__main__.TestSetSubclass)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "../Lib/test/test_set.py", line 302, in test_discard
-    self.assert_(self.thetype(self.word) in s)
-AssertionError
-
-======================================================================
-FAIL: test_hash (__main__.TestSetSubclass)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "../Lib/test/test_set.py", line 265, in test_hash
-    self.assertRaises(TypeError, hash, self.s)
-AssertionError: TypeError not raised
-
-======================================================================
-FAIL: test_remove (__main__.TestSetSubclass)
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "../Lib/test/test_set.py", line 291, in test_remove
-    self.assert_(self.thetype(self.word) in s)
-AssertionError
+(Nothing is broken at the moment AFAIK.)

Modified: python/branches/p3yk/Include/object.h
==============================================================================
--- python/branches/p3yk/Include/object.h	(original)
+++ python/branches/p3yk/Include/object.h	Tue Aug 22 01:36:26 2006
@@ -368,6 +368,7 @@
 
 /* Generic operations on objects */
 PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
+PyAPI_FUNC(void) _Py_Break(void);
 PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
 PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *);

Modified: python/branches/p3yk/Lib/test/mapping_tests.py
==============================================================================
--- python/branches/p3yk/Lib/test/mapping_tests.py	(original)
+++ python/branches/p3yk/Lib/test/mapping_tests.py	Tue Aug 22 01:36:26 2006
@@ -545,6 +545,8 @@
         class BadEq(object):
             def __eq__(self, other):
                 raise Exc()
+            def __hash__(self):
+                return 24
 
         d = self._empty_mapping()
         d[BadEq()] = 42
@@ -630,6 +632,8 @@
         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})

Modified: python/branches/p3yk/Lib/test/test_dict.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_dict.py	(original)
+++ python/branches/p3yk/Lib/test/test_dict.py	Tue Aug 22 01:36:26 2006
@@ -76,6 +76,8 @@
         class BadEq(object):
             def __eq__(self, other):
                 raise Exc()
+            def __hash__(self):
+                return 24
 
         d = {}
         d[BadEq()] = 42
@@ -375,6 +377,8 @@
         class BadCmp(object):
             def __eq__(self, other):
                 raise Exc()
+            def __hash__(self):
+                return 42
 
         d1 = {BadCmp(): 1}
         d2 = {1: 1}

Modified: python/branches/p3yk/Objects/object.c
==============================================================================
--- python/branches/p3yk/Objects/object.c	(original)
+++ python/branches/p3yk/Objects/object.c	Tue Aug 22 01:36:26 2006
@@ -320,9 +320,16 @@
 	return internal_print(op, fp, flags, 0);
 }
 
+/* For debugging convenience.  Set a breakpoint here and call it from your DLL */
+void
+_Py_Break(void)
+{
+}
+
 
 /* For debugging convenience.  See Misc/gdbinit for some useful gdb hooks */
-void _PyObject_Dump(PyObject* op)
+void
+_PyObject_Dump(PyObject* op)
 {
 	if (op == NULL)
 		fprintf(stderr, "NULL\n");

Modified: python/branches/p3yk/Objects/typeobject.c
==============================================================================
--- python/branches/p3yk/Objects/typeobject.c	(original)
+++ python/branches/p3yk/Objects/typeobject.c	Tue Aug 22 01:36:26 2006
@@ -2847,6 +2847,33 @@
 	COPYVAL(tp_dictoffset);
 }
 
+/* Map rich comparison operators to their __xx__ namesakes */
+static char *name_op[] = {
+	"__lt__",
+	"__le__",
+	"__eq__",
+	"__ne__",
+	"__gt__",
+	"__ge__",
+	/* These are only for overrides_cmp_or_hash(): */ 
+	"__cmp__",
+	"__hash__",
+};
+
+static int
+overrides_cmp_or_hash(PyTypeObject *type)
+{
+	int i;
+	PyObject *dict = type->tp_dict;
+
+	assert(dict != NULL);
+	for (i = 0; i < 8; i++) {
+		if (PyDict_GetItemString(dict, name_op[i]) != NULL)
+			return 1;
+	}
+	return 0;
+}
+
 static void
 inherit_slots(PyTypeObject *type, PyTypeObject *base)
 {
@@ -2970,9 +2997,12 @@
 	COPYSLOT(tp_call);
 	COPYSLOT(tp_str);
 	{
+		/* Copy comparison-related slots only when
+		   not overriding them anywhere */
 		if (type->tp_compare == NULL &&
 		    type->tp_richcompare == NULL &&
-		    type->tp_hash == NULL)
+		    type->tp_hash == NULL &&
+		    !overrides_cmp_or_hash(type))
 		{
 			type->tp_compare = base->tp_compare;
 			type->tp_richcompare = base->tp_richcompare;
@@ -3020,6 +3050,10 @@
 	PyTypeObject *base;
 	Py_ssize_t i, n;
 
+	if (strcmp(type->tp_name, "C") == 0) {
+		_Py_Break();
+	}
+
 	if (type->tp_flags & Py_TPFLAGS_READY) {
 		assert(type->tp_dict != NULL);
 		return 0;
@@ -3150,6 +3184,18 @@
 		}
 	}
 
+	/* Hack for tp_hash and __hash__.
+	   If after all that, tp_hash is still NULL, and __hash__ is not in
+	   tp_dict, set tp_dict['__hash__'] equal to None.
+	   This signals that __hash__ is not inherited.
+	 */
+	if (type->tp_hash == NULL) {
+		if (PyDict_GetItemString(type->tp_dict, "__hash__") == NULL) {
+			if (PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0)
+				goto error;
+		}
+	}
+
 	/* Some more special stuff */
 	base = type->tp_base;
 	if (base != NULL) {
@@ -4450,16 +4496,6 @@
 	return 0;
 }
 
-/* Map rich comparison operators to their __xx__ namesakes */
-static char *name_op[] = {
-	"__lt__",
-	"__le__",
-	"__eq__",
-	"__ne__",
-	"__gt__",
-	"__ge__",
-};
-
 static PyObject *
 half_richcompare(PyObject *self, PyObject *other, int op)
 {


More information about the Python-3000-checkins mailing list