Issue #14417: Mutating a dict during lookup now restarts the lookup instead of raising a RuntimeError (undoes issue #14205).

This commit is contained in:
Antoine Pitrou 2012-05-13 20:48:01 +02:00
parent 7feb9f4225
commit 9a2349030a
5 changed files with 15 additions and 23 deletions

View File

@ -2210,10 +2210,6 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
See :class:`collections.Counter` for a complete implementation including
other methods helpful for accumulating and managing tallies.
.. versionchanged:: 3.3
If the dict is modified during the lookup, a :exc:`RuntimeError`
exception is now raised.
.. describe:: d[key] = value
Set ``d[key]`` to *value*.

View File

@ -557,13 +557,6 @@ Some smaller changes made to the core Python language are:
(:issue:`12170`)
* A dict lookup now raises a :exc:`RuntimeError` if the dict is modified during
the lookup. If you implement your own comparison function for objects used
as dict keys and the dict is shared by multiple threads, access to the dict
should be protected by a lock.
(:issue:`14205`)
* New methods have been added to :class:`list` and :class:`bytearray`:
``copy()`` and ``clear()``.

View File

@ -411,7 +411,7 @@ class DictTest(unittest.TestCase):
d[i+1] = 1
def test_mutating_lookup(self):
# changing dict during a lookup
# changing dict during a lookup (issue #14417)
class NastyKey:
mutate_dict = None
@ -433,9 +433,8 @@ class DictTest(unittest.TestCase):
key2 = NastyKey(2)
d = {key1: 1}
NastyKey.mutate_dict = (d, key1)
with self.assertRaisesRegex(RuntimeError,
'dictionary changed size during lookup'):
d[key2] = 2
d[key2] = 2
self.assertEqual(d, {key2: 2})
def test_repr(self):
d = {}

View File

@ -10,6 +10,9 @@ What's New in Python 3.3.0 Alpha 4?
Core and Builtins
-----------------
- Issue #14417: Mutating a dict during lookup now restarts the lookup instead
of raising a RuntimeError (undoes issue #14205).
- Issue #14738: Speed-up UTF-8 decoding on non-ASCII data. Patch by Serhiy
Storchaka.

View File

@ -439,12 +439,15 @@ lookdict(PyDictObject *mp, PyObject *key,
register size_t i;
register size_t perturb;
register PyDictKeyEntry *freeslot;
register size_t mask = DK_MASK(mp->ma_keys);
PyDictKeyEntry *ep0 = &mp->ma_keys->dk_entries[0];
register size_t mask;
PyDictKeyEntry *ep0;
register PyDictKeyEntry *ep;
register int cmp;
PyObject *startkey;
top:
mask = DK_MASK(mp->ma_keys);
ep0 = &mp->ma_keys->dk_entries[0];
i = (size_t)hash & mask;
ep = &ep0[i];
if (ep->me_key == NULL || ep->me_key == key) {
@ -468,9 +471,8 @@ lookdict(PyDictObject *mp, PyObject *key,
}
}
else {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during lookup");
return NULL;
/* The dict was mutated, restart */
goto top;
}
}
freeslot = NULL;
@ -510,9 +512,8 @@ lookdict(PyDictObject *mp, PyObject *key,
}
}
else {
PyErr_SetString(PyExc_RuntimeError,
"dictionary changed size during lookup");
return NULL;
/* The dict was mutated, restart */
goto top;
}
}
else if (ep->me_key == dummy && freeslot == NULL)