Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f1f2f68

Browse files
committed
Recorded merge of revisions 68051 via svnmerge from
svn+ssh://[email protected]/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 ........
1 parent 4450dcf commit f1f2f68

4 files changed

Lines changed: 136 additions & 1 deletion

File tree

Lib/test/test_hash.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,30 @@ def test_not_hashable(self):
103103
self.assertFalse(isinstance(obj, Hashable), repr(obj))
104104

105105

106+
# Issue #4701: Check that some builtin types are correctly hashable
107+
class DefaultIterSeq(object):
108+
seq = range(10)
109+
def __len__(self):
110+
return len(self.seq)
111+
def __getitem__(self, index):
112+
return self.seq[index]
113+
114+
class HashBuiltinsTestCase(unittest.TestCase):
115+
hashes_to_check = [range(10),
116+
enumerate(range(10)),
117+
iter(DefaultIterSeq()),
118+
iter(lambda: 0, 0),
119+
]
120+
121+
def test_hashes(self):
122+
_default_hash = object.__hash__
123+
for obj in self.hashes_to_check:
124+
self.assertEqual(hash(obj), _default_hash(obj))
125+
106126
def test_main():
107127
support.run_unittest(HashEqualityTestCase,
108-
HashInheritanceTestCase)
128+
HashInheritanceTestCase,
129+
HashBuiltinsTestCase)
109130

110131

111132
if __name__ == "__main__":

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #4701: PyObject_Hash now implicitly calls PyType_Ready on types
16+
where the tp_hash and tp_dict slots are both NULL.
17+
1518
- Issue #4759: None is now allowed as the first argument of
1619
bytearray.translate(). It was always allowed for bytes.translate().
1720

Modules/_testcapimodule.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,105 @@ test_dict_iteration(PyObject* self)
175175
}
176176

177177

178+
/* Issue #4701: Check that PyObject_Hash implicitly calls
179+
* PyType_Ready if it hasn't already been called
180+
*/
181+
static PyTypeObject _HashInheritanceTester_Type = {
182+
PyVarObject_HEAD_INIT(&PyType_Type, 0)
183+
"hashinheritancetester", /* Name of this type */
184+
sizeof(PyObject), /* Basic object size */
185+
0, /* Item size for varobject */
186+
(destructor)PyObject_Del, /* tp_dealloc */
187+
0, /* tp_print */
188+
0, /* tp_getattr */
189+
0, /* tp_setattr */
190+
0, /* tp_compare */
191+
0, /* tp_repr */
192+
0, /* tp_as_number */
193+
0, /* tp_as_sequence */
194+
0, /* tp_as_mapping */
195+
0, /* tp_hash */
196+
0, /* tp_call */
197+
0, /* tp_str */
198+
PyObject_GenericGetAttr, /* tp_getattro */
199+
0, /* tp_setattro */
200+
0, /* tp_as_buffer */
201+
Py_TPFLAGS_DEFAULT, /* tp_flags */
202+
0, /* tp_doc */
203+
0, /* tp_traverse */
204+
0, /* tp_clear */
205+
0, /* tp_richcompare */
206+
0, /* tp_weaklistoffset */
207+
0, /* tp_iter */
208+
0, /* tp_iternext */
209+
0, /* tp_methods */
210+
0, /* tp_members */
211+
0, /* tp_getset */
212+
0, /* tp_base */
213+
0, /* tp_dict */
214+
0, /* tp_descr_get */
215+
0, /* tp_descr_set */
216+
0, /* tp_dictoffset */
217+
0, /* tp_init */
218+
0, /* tp_alloc */
219+
PyType_GenericNew, /* tp_new */
220+
};
221+
222+
static PyObject*
223+
test_lazy_hash_inheritance(PyObject* self)
224+
{
225+
PyTypeObject *type;
226+
PyObject *obj;
227+
long hash;
228+
229+
type = &_HashInheritanceTester_Type;
230+
obj = PyObject_New(PyObject, type);
231+
if (obj == NULL) {
232+
PyErr_Clear();
233+
PyErr_SetString(
234+
TestError,
235+
"test_lazy_hash_inheritance: failed to create object");
236+
return NULL;
237+
}
238+
239+
if (type->tp_dict != NULL) {
240+
PyErr_SetString(
241+
TestError,
242+
"test_lazy_hash_inheritance: type initialised too soon");
243+
Py_DECREF(obj);
244+
return NULL;
245+
}
246+
247+
hash = PyObject_Hash(obj);
248+
if ((hash == -1) && PyErr_Occurred()) {
249+
PyErr_Clear();
250+
PyErr_SetString(
251+
TestError,
252+
"test_lazy_hash_inheritance: could not hash object");
253+
Py_DECREF(obj);
254+
return NULL;
255+
}
256+
257+
if (type->tp_dict == NULL) {
258+
PyErr_SetString(
259+
TestError,
260+
"test_lazy_hash_inheritance: type not initialised by hash()");
261+
Py_DECREF(obj);
262+
return NULL;
263+
}
264+
265+
if (type->tp_hash != PyType_Type.tp_hash) {
266+
PyErr_SetString(
267+
TestError,
268+
"test_lazy_hash_inheritance: unexpected hash function");
269+
Py_DECREF(obj);
270+
return NULL;
271+
}
272+
273+
Py_RETURN_NONE;
274+
}
275+
276+
178277
/* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG)
179278
PyLong_{As, From}{Unsigned,}LongLong().
180279
@@ -1036,6 +1135,7 @@ static PyMethodDef TestMethods[] = {
10361135
{"test_config", (PyCFunction)test_config, METH_NOARGS},
10371136
{"test_list_api", (PyCFunction)test_list_api, METH_NOARGS},
10381137
{"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS},
1138+
{"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS},
10391139
{"test_long_api", (PyCFunction)test_long_api, METH_NOARGS},
10401140
{"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS},
10411141
{"test_k_code", (PyCFunction)test_k_code, METH_NOARGS},

Objects/object.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,17 @@ PyObject_Hash(PyObject *v)
846846
PyTypeObject *tp = Py_TYPE(v);
847847
if (tp->tp_hash != NULL)
848848
return (*tp->tp_hash)(v);
849+
/* To keep to the general practice that inheriting
850+
* solely from object in C code should work without
851+
* an explicit call to PyType_Ready, we implicitly call
852+
* PyType_Ready here and then check the tp_hash slot again
853+
*/
854+
if (tp->tp_dict == NULL) {
855+
if (PyType_Ready(tp) < 0)
856+
return -1;
857+
if (tp->tp_hash != NULL)
858+
return (*tp->tp_hash)(v);
859+
}
849860
/* Otherwise, the object can't be hashed */
850861
return PyObject_HashNotImplemented(v);
851862
}

0 commit comments

Comments
 (0)