+import contextlib
import unittest
from collections import OrderedDict, UserDict
from types import MappingProxyType
# CRASHES contains({}, NULL)
# CRASHES contains(NULL, b'a')
+ @contextlib.contextmanager
+ def frozendict_does_not_support(self, what):
+ errmsg = f'frozendict object does not support item {what}'
+ with self.assertRaisesRegex(TypeError, errmsg):
+ yield
+
def test_dict_setitem(self):
# Test PyDict_SetItem()
setitem = _testlimitedcapi.dict_setitem
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
self.assertRaises(TypeError, setitem, {}, [], 5) # unhashable
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ setitem(test_type(), 'a', 5)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, setitem, test_type(), 'a', 5)
# CRASHES setitem({}, NULL, 5)
# CRASHES setitem({}, 'a', NULL)
self.assertEqual(dct, {'a': 5, '\U0001f40d': 8})
self.assertRaises(UnicodeDecodeError, setitemstring, {}, INVALID_UTF8, 5)
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ setitemstring(test_type(), b'a', 5)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, setitemstring, test_type(), b'a', 5)
# CRASHES setitemstring({}, NULL, 5)
# CRASHES setitemstring({}, b'a', NULL)
self.assertEqual(dct, {'c': 2})
self.assertRaises(TypeError, delitem, {}, []) # unhashable
- for test_type in NOT_DICT_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('deletion'):
+ delitem(test_type({'a': 1}), 'a')
+ for test_type in MAPPING_TYPES:
self.assertRaises(SystemError, delitem, test_type({'a': 1}), 'a')
for test_type in OTHER_TYPES:
self.assertRaises(SystemError, delitem, test_type(), 'a')
self.assertEqual(dct, {'c': 2})
self.assertRaises(UnicodeDecodeError, delitemstring, {}, INVALID_UTF8)
- for test_type in NOT_DICT_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('deletion'):
+ delitemstring(test_type({'a': 1}), b'a')
+ for test_type in MAPPING_TYPES:
self.assertRaises(SystemError, delitemstring, test_type({'a': 1}), b'a')
for test_type in OTHER_TYPES:
self.assertRaises(SystemError, delitemstring, test_type(), b'a')
self.assertEqual(dct, {'a': 5})
self.assertRaises(TypeError, setdefault, {}, [], 5) # unhashable
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ setdefault(test_type(), 'a', 5)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, setdefault, test_type(), 'a', 5)
# CRASHES setdefault({}, NULL, 5)
# CRASHES setdefault({}, 'a', NULL)
self.assertEqual(dct, {'a': 5})
self.assertRaises(TypeError, setdefault, {}, [], 5) # unhashable
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ setdefault(test_type(), 'a', 5)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, setdefault, test_type(), 'a', 5)
# CRASHES setdefault({}, NULL, 5)
# CRASHES setdefault({}, 'a', NULL)
self.assertRaises(AttributeError, update, {}, [])
self.assertRaises(AttributeError, update, {}, 42)
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ update(test_type(), {})
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, update, test_type(), {})
self.assertRaises(SystemError, update, {}, NULL)
self.assertRaises(SystemError, update, NULL, {})
self.assertRaises(AttributeError, merge, {}, [], 0)
self.assertRaises(AttributeError, merge, {}, 42, 0)
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ merge(test_type(), {}, 0)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, merge, test_type(), {}, 0)
self.assertRaises(SystemError, merge, {}, NULL, 0)
self.assertRaises(SystemError, merge, NULL, {}, 0)
self.assertRaises(ValueError, mergefromseq2, {}, [(1, 2, 3)], 0)
self.assertRaises(TypeError, mergefromseq2, {}, [1], 0)
self.assertRaises(TypeError, mergefromseq2, {}, 42, 0)
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('assignment'):
+ mergefromseq2(test_type(), [], 0)
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
self.assertRaises(SystemError, mergefromseq2, test_type(), [], 0)
# CRASHES mergefromseq2({}, NULL, 0)
# CRASHES mergefromseq2(NULL, {}, 0)
dict_pop(mydict, not_hashable_key)
# wrong dict type
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('deletion'):
+ dict_pop(test_type(), "key")
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
not_dict = test_type()
self.assertRaises(SystemError, dict_pop, not_dict, "key")
self.assertRaises(SystemError, dict_pop_null, not_dict, "key")
self.assertRaises(UnicodeDecodeError, dict_popstring_null, mydict, INVALID_UTF8)
# wrong dict type
- for test_type in NOT_DICT_TYPES + OTHER_TYPES:
+ for test_type in FROZENDICT_TYPES:
+ with self.frozendict_does_not_support('deletion'):
+ dict_popstring(test_type(), "key")
+ for test_type in MAPPING_TYPES + OTHER_TYPES:
not_dict = test_type()
self.assertRaises(SystemError, dict_popstring, not_dict, "key")
self.assertRaises(SystemError, dict_popstring_null, not_dict, "key")
return builtins;
}
+#define frozendict_does_not_support(WHAT) \
+ PyErr_SetString(PyExc_TypeError, "frozendict object does " \
+ "not support item " WHAT)
+
/* Consumes references to key and value */
static int
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
int
PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
{
+ assert(key);
+ assert(value);
+
if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(op)) {
+ frozendict_does_not_support("assignment");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}
- assert(key);
- assert(value);
+
return _PyDict_SetItem_Take2((PyDictObject *)op,
Py_NewRef(key), Py_NewRef(value));
}
_PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
Py_hash_t hash)
{
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
assert(key);
assert(value);
assert(hash != -1);
+ if (!PyDict_Check(op)) {
+ if (PyFrozenDict_Check(op)) {
+ frozendict_does_not_support("assignment");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
+ return -1;
+ }
+
int res;
Py_BEGIN_CRITICAL_SECTION(op);
res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)op, key, value, hash);
int
_PyDict_DelItem_KnownHash_LockHeld(PyObject *op, PyObject *key, Py_hash_t hash)
{
- Py_ssize_t ix;
- PyObject *old_value;
-
if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(op)) {
+ frozendict_does_not_support("deletion");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}
+
+ Py_ssize_t ix;
+ PyObject *old_value;
PyDictObject *mp = (PyDictObject *)op;
assert(can_modify_dict(mp));
if (result) {
*result = NULL;
}
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(op)) {
+ frozendict_does_not_support("deletion");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}
PyDictObject *dict = (PyDictObject *)op;
assert(d != NULL);
assert(seq2 != NULL);
if (!PyDict_Check(d)) {
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(d)) {
+ frozendict_does_not_support("assignment");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}
* PyMapping_Keys() and PyObject_GetItem() be supported.
*/
if (a == NULL || !PyDict_Check(a) || b == NULL) {
- PyErr_BadInternalCall();
+ if (a != NULL && PyFrozenDict_Check(a)) {
+ frozendict_does_not_support("assignment");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}
return dict_merge(a, b, override);
dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_value,
PyObject **result, int incref_result)
{
- PyDictObject *mp = (PyDictObject *)d;
- PyObject *value;
- Py_hash_t hash;
- Py_ssize_t ix;
-
if (!PyDict_Check(d)) {
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(d)) {
+ frozendict_does_not_support("assignment");
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
if (result) {
*result = NULL;
}
}
assert(can_modify_dict((PyDictObject*)d));
+ PyDictObject *mp = (PyDictObject *)d;
+ PyObject *value;
+ Py_hash_t hash;
+ Py_ssize_t ix;
+
hash = _PyObject_HashFast(key);
if (hash == -1) {
dict_unhashable_type(d, key);
_PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
{
if (!PyDict_Check(dict)) {
- PyErr_BadInternalCall();
+ if (PyFrozenDict_Check(dict)) {
+ if (value == NULL) {
+ frozendict_does_not_support("deletion");
+ }
+ else {
+ frozendict_does_not_support("assignment");
+ }
+ }
+ else {
+ PyErr_BadInternalCall();
+ }
return -1;
}