self.assertEqual(list(unpickled), expected)
self.assertEqual(list(it), expected)
+ def test_unhashable_key(self):
+ d = frozendict(a=1)
+ key = [1, 2, 3]
+
+ def check_unhashable_key():
+ msg = "cannot use 'list' as a frozendict key (unhashable type: 'list')"
+ return self.assertRaisesRegex(TypeError, re.escape(msg))
+
+ with check_unhashable_key():
+ key in d
+ with check_unhashable_key():
+ d[key]
+ with check_unhashable_key():
+ d.get(key)
+
+ # Only TypeError exception is overridden,
+ # other exceptions are left unchanged.
+ class HashError:
+ def __hash__(self):
+ raise KeyError('error')
+
+ key2 = HashError()
+ with self.assertRaises(KeyError):
+ key2 in d
+ with self.assertRaises(KeyError):
+ d[key2]
+ with self.assertRaises(KeyError):
+ d.get(key2)
+
if __name__ == "__main__":
unittest.main()
}
static void
-dict_unhashable_type(PyObject *key)
+dict_unhashable_type(PyObject *op, PyObject *key)
{
PyObject *exc = PyErr_GetRaisedException();
assert(exc != NULL);
return;
}
- PyErr_Format(PyExc_TypeError,
- "cannot use '%T' as a dict key (%S)",
- key, exc);
+ const char *errmsg;
+ if (PyObject_IsInstance(op, (PyObject*)&PyFrozenDict_Type)) {
+ errmsg = "cannot use '%T' as a frozendict key (%S)";
+ }
+ else {
+ errmsg = "cannot use '%T' as a dict key (%S)";
+ }
+ PyErr_Format(PyExc_TypeError, errmsg, key, exc);
Py_DECREF(exc);
}
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type((PyObject*)mp, key);
return -1;
}
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(op, key);
*result = NULL;
return -1;
}
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type((PyObject*)op, key);
*result = NULL;
return -1;
}
}
hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(op, key);
return NULL;
}
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type((PyObject*)mp, key);
Py_DECREF(key);
Py_DECREF(value);
return -1;
assert(key);
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(op, key);
return -1;
}
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(op, key);
if (result) {
*result = NULL;
}
hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(self, key);
return NULL;
}
ix = _Py_dict_lookup_threadsafe(mp, key, hash, &value);
hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type((PyObject*)self, key);
return NULL;
}
ix = _Py_dict_lookup_threadsafe(self, key, hash, &val);
hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(d, key);
if (result) {
*result = NULL;
}
{
Py_hash_t hash = _PyObject_HashFast(key);
if (hash == -1) {
- dict_unhashable_type(key);
+ dict_unhashable_type(op, key);
return -1;
}
if (value == NULL) {
Py_hash_t hash = _PyObject_HashFast(name);
if (hash == -1) {
- dict_unhashable_type(name);
+ dict_unhashable_type((PyObject*)dict, name);
return -1;
}
return _PyDict_DelItem_KnownHash_LockHeld((PyObject *)dict, name, hash);