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

nick.coghlan python-checkins at python.org
Tue Dec 30 02:36:00 CET 2008


Author: nick.coghlan
Date: Tue Dec 30 02:36:00 2008
New Revision: 68052
Log:
Merged revisions 68051 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk
........
 r68051 | nick.coghlan | 2008年12月30日 11:18:48 +1000 (2008年12月30日) | 1 line
 
 Issue #4701: implicitly call PyType_Ready from PyObject_Hash
........
Modified:
 python/branches/release26-maint/ (props changed)
 python/branches/release26-maint/Lib/test/test_hash.py
 python/branches/release26-maint/Misc/NEWS
 python/branches/release26-maint/Modules/_testcapimodule.c
 python/branches/release26-maint/Objects/object.c
Modified: python/branches/release26-maint/Lib/test/test_hash.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_hash.py	(original)
+++ python/branches/release26-maint/Lib/test/test_hash.py	Tue Dec 30 02:36:00 2008
@@ -111,9 +111,32 @@
 self.assertFalse(isinstance(obj, Hashable), repr(obj))
 
 
+# Issue #4701: Check that some builtin types are correctly hashable
+# (This test only used to fail in Python 3.0, but has been included
+# in 2.x along with the lazy call to PyType_Ready in PyObject_Hash)
+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 = [xrange(10),
+ enumerate(xrange(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():
 test_support.run_unittest(HashEqualityTestCase,
- HashInheritanceTestCase)
+ HashInheritanceTestCase,
+ HashBuiltinsTestCase)
 
 
 if __name__ == "__main__":
Modified: python/branches/release26-maint/Misc/NEWS
==============================================================================
--- python/branches/release26-maint/Misc/NEWS	(original)
+++ python/branches/release26-maint/Misc/NEWS	Tue Dec 30 02:36:00 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/release26-maint/Modules/_testcapimodule.c
==============================================================================
--- python/branches/release26-maint/Modules/_testcapimodule.c	(original)
+++ python/branches/release26-maint/Modules/_testcapimodule.c	Tue Dec 30 02:36:00 2008
@@ -173,6 +173,106 @@
 }
 
 
+/* Issue #4701: Check that PyObject_Hash implicitly calls
+ * PyType_Ready if it hasn't already been called
+ */
+static PyTypeObject _HashInheritanceTester_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,			/* Number of items for varobject */
+	"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().
 
@@ -805,6 +905,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/release26-maint/Objects/object.c
==============================================================================
--- python/branches/release26-maint/Objects/object.c	(original)
+++ python/branches/release26-maint/Objects/object.c	Tue Dec 30 02:36:00 2008
@@ -1100,6 +1100,17 @@
 	PyTypeObject *tp = v->ob_type;
 	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);
+	}
 	if (tp->tp_compare == NULL && RICHCOMPARE(tp) == NULL) {
 		return _Py_HashPointer(v); /* Use address as hash value */
 	}


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /