[Python-checkins] r68060 - in python/branches/release30-maint: Lib/test/test_hash.py Misc/NEWS Modules/_testcapimodule.c Objects/object.c

nick.coghlan python-checkins at python.org
Tue Dec 30 08:41:03 CET 2008


Author: nick.coghlan
Date: Tue Dec 30 08:41:03 2008
New Revision: 68060

Log:
Recorded merge of revisions 68058 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/branches/py3k

................
  r68058 | nick.coghlan | 2008-12-30 17:29:12 +1000 (Tue, 30 Dec 2008) | 9 lines
  
  Recorded merge of revisions 68051 via svnmerge from 
  svn+ssh://pythondev@svn.python.org/python/trunk
  
  ........
    r68051 | nick.coghlan | 2008-12-30 11:18:48 +1000 (Tue, 30 Dec 2008) | 1 line
    
    Issue #4701: implicitly call PyType_Ready from PyObject_Hash
  ........
................


Modified:
   python/branches/release30-maint/   (props changed)
   python/branches/release30-maint/Lib/test/test_hash.py
   python/branches/release30-maint/Misc/NEWS
   python/branches/release30-maint/Modules/_testcapimodule.c
   python/branches/release30-maint/Objects/object.c

Modified: python/branches/release30-maint/Lib/test/test_hash.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_hash.py	(original)
+++ python/branches/release30-maint/Lib/test/test_hash.py	Tue Dec 30 08:41:03 2008
@@ -103,9 +103,30 @@
             self.assertFalse(isinstance(obj, Hashable), repr(obj))
 
 
+# Issue #4701: Check that some builtin types are correctly hashable
+class DefaultIterSeq(object):
+    seq = range(10)
+    def __len__(self):
+        return len(self.seq)
+    def __getitem__(self, index):
+        return self.seq[index]
+
+class HashBuiltinsTestCase(unittest.TestCase):
+    hashes_to_check = [range(10),
+                       enumerate(range(10)),
+                       iter(DefaultIterSeq()),
+                       iter(lambda: 0, 0),
+                      ]
+
+    def test_hashes(self):
+        _default_hash = object.__hash__
+        for obj in self.hashes_to_check:
+            self.assertEqual(hash(obj), _default_hash(obj))
+
 def test_main():
     support.run_unittest(HashEqualityTestCase,
-                         HashInheritanceTestCase)
+                              HashInheritanceTestCase,
+                              HashBuiltinsTestCase)
 
 
 if __name__ == "__main__":

Modified: python/branches/release30-maint/Misc/NEWS
==============================================================================
--- python/branches/release30-maint/Misc/NEWS	(original)
+++ python/branches/release30-maint/Misc/NEWS	Tue Dec 30 08:41:03 2008
@@ -12,6 +12,9 @@
 Core and Builtins
 -----------------
 
+- Issue #4701: PyObject_Hash now implicitly calls PyType_Ready on types
+  where the tp_hash and tp_dict slots are both NULL.
+
 - Issue #4759: fix a segfault for bytearray.translate(x, None).
 
 - Added test case to ensure attempts to read from a file opened for writing

Modified: python/branches/release30-maint/Modules/_testcapimodule.c
==============================================================================
--- python/branches/release30-maint/Modules/_testcapimodule.c	(original)
+++ python/branches/release30-maint/Modules/_testcapimodule.c	Tue Dec 30 08:41:03 2008
@@ -175,6 +175,105 @@
 }
 
 
+/* Issue #4701: Check that PyObject_Hash implicitly calls
+ *   PyType_Ready if it hasn't already been called
+ */
+static PyTypeObject _HashInheritanceTester_Type = {
+	PyVarObject_HEAD_INIT(&PyType_Type, 0)
+	"hashinheritancetester",	/* Name of this type */
+	sizeof(PyObject),	/* Basic object size */
+	0,			/* Item size for varobject */
+	(destructor)PyObject_Del, /* tp_dealloc */
+	0,			/* tp_print */
+	0,			/* tp_getattr */
+	0,			/* tp_setattr */
+	0,			/* tp_compare */
+	0,			/* tp_repr */
+	0,			/* tp_as_number */
+	0,			/* tp_as_sequence */
+	0,			/* tp_as_mapping */
+	0,			/* tp_hash */
+	0,			/* tp_call */
+	0,			/* tp_str */
+	PyObject_GenericGetAttr,  /* tp_getattro */
+	0,			/* tp_setattro */
+	0,			/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT,	/* tp_flags */
+	0,			/* tp_doc */
+	0,			/* tp_traverse */
+	0,			/* tp_clear */
+	0,			/* tp_richcompare */
+	0,			/* tp_weaklistoffset */
+	0,			/* tp_iter */
+	0,			/* tp_iternext */
+	0,			/* tp_methods */
+	0,			/* tp_members */
+	0,			/* tp_getset */
+	0,			/* tp_base */
+	0,			/* tp_dict */
+	0,			/* tp_descr_get */
+	0,			/* tp_descr_set */
+	0,			/* tp_dictoffset */
+	0,			/* tp_init */
+	0,			/* tp_alloc */
+	PyType_GenericNew,		/* tp_new */
+};
+
+static PyObject*
+test_lazy_hash_inheritance(PyObject* self)
+{
+	PyTypeObject *type;
+	PyObject *obj;
+	long hash;
+
+	type = &_HashInheritanceTester_Type;
+	obj = PyObject_New(PyObject, type);
+	if (obj == NULL) {
+		PyErr_Clear();
+		PyErr_SetString(
+			TestError,
+			"test_lazy_hash_inheritance: failed to create object");
+		return NULL;
+	}
+
+	if (type->tp_dict != NULL) {
+		PyErr_SetString(
+			TestError,
+			"test_lazy_hash_inheritance: type initialised too soon");
+		Py_DECREF(obj);
+		return NULL;
+	}
+
+	hash = PyObject_Hash(obj);
+	if ((hash == -1) && PyErr_Occurred()) {
+		PyErr_Clear();
+		PyErr_SetString(
+			TestError,
+			"test_lazy_hash_inheritance: could not hash object");
+		Py_DECREF(obj);
+		return NULL;
+	}
+
+	if (type->tp_dict == NULL) {
+		PyErr_SetString(
+			TestError,
+			"test_lazy_hash_inheritance: type not initialised by hash()");
+		Py_DECREF(obj);
+		return NULL;
+	}
+
+	if (type->tp_hash != PyType_Type.tp_hash) {
+		PyErr_SetString(
+			TestError,
+			"test_lazy_hash_inheritance: unexpected hash function");
+		Py_DECREF(obj);
+		return NULL;
+	}
+
+	Py_RETURN_NONE;
+}
+
+
 /* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG)
    PyLong_{As, From}{Unsigned,}LongLong().
 
@@ -1036,6 +1135,7 @@
 	{"test_config",		(PyCFunction)test_config,	 METH_NOARGS},
 	{"test_list_api",	(PyCFunction)test_list_api,	 METH_NOARGS},
 	{"test_dict_iteration",	(PyCFunction)test_dict_iteration,METH_NOARGS},
+	{"test_lazy_hash_inheritance",	(PyCFunction)test_lazy_hash_inheritance,METH_NOARGS},
 	{"test_long_api",	(PyCFunction)test_long_api,	 METH_NOARGS},
 	{"test_long_numbits",	(PyCFunction)test_long_numbits,	 METH_NOARGS},
 	{"test_k_code",		(PyCFunction)test_k_code,	 METH_NOARGS},

Modified: python/branches/release30-maint/Objects/object.c
==============================================================================
--- python/branches/release30-maint/Objects/object.c	(original)
+++ python/branches/release30-maint/Objects/object.c	Tue Dec 30 08:41:03 2008
@@ -846,6 +846,17 @@
 	PyTypeObject *tp = Py_TYPE(v);
 	if (tp->tp_hash != NULL)
 		return (*tp->tp_hash)(v);
+	/* To keep to the general practice that inheriting
+	 * solely from object in C code should work without
+	 * an explicit call to PyType_Ready, we implicitly call
+	 * PyType_Ready here and then check the tp_hash slot again
+	 */
+	if (tp->tp_dict == NULL) {
+		if (PyType_Ready(tp) < 0)
+			return -1;
+		if (tp->tp_hash != NULL)
+			return (*tp->tp_hash)(v);
+	}
 	/* Otherwise, the object can't be hashed */
 	return PyObject_HashNotImplemented(v);
 }


More information about the Python-checkins mailing list