diff options
-rw-r--r-- | Doc/library/decimal.rst | 21 | ||||
-rw-r--r-- | Lib/test/test_dict.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Objects/dictobject.c | 67 |
4 files changed, 60 insertions, 39 deletions
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index ef8b43f..919ebe4 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -710,12 +710,21 @@ Decimal objects .. method:: remainder_near(other[, context]) - Compute the modulo as either a positive or negative value depending on - which is closest to zero. For instance, ``Decimal(10).remainder_near(6)`` - returns ``Decimal('-2')`` which is closer to zero than ``Decimal('4')``. - - If both are equally close, the one chosen will have the same sign as - *self*. + Return the remainder from dividing *self* by *other*. This differs from + ``self % other`` in that the sign of the remainder is chosen so as to + minimize its absolute value. More precisely, the return value is + ``self - n * other`` where ``n`` is the integer nearest to the exact + value of ``self / other``, and if two integers are equally near then the + even one is chosen. + + If the result is zero then its sign will be the sign of *self*. + + >>> Decimal(18).remainder_near(Decimal(10)) + Decimal('-2') + >>> Decimal(25).remainder_near(Decimal(10)) + Decimal('5') + >>> Decimal(35).remainder_near(Decimal(10)) + Decimal('-5') .. method:: rotate(other[, context]) diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index d2740a3..9666f9a 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -254,6 +254,14 @@ class DictTest(unittest.TestCase): d = dict(zip(range(6), range(6))) self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) + class baddict3(dict): + def __new__(cls): + return d + d = {i : i for i in range(10)} + res = d.copy() + res.update(a=None, b=None, c=None) + self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) + def test_copy(self): d = {1:1, 2:2, 3:3} self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) @@ -10,6 +10,9 @@ What's New in Python 3.2.4 Core and Builtins ----------------- +- Issue #16345: Fix an infinite loop when ``fromkeys`` on a dict subclass + received a nonempty dict from the constructor. + - Issue #16197: Update winreg docstrings and documentation to match code. Patch by Zachary Ware. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 27de10d..c10bfcc 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1335,49 +1335,50 @@ dict_fromkeys(PyObject *cls, PyObject *args) if (d == NULL) return NULL; - if (PyDict_CheckExact(d) && PyDict_CheckExact(seq)) { - PyDictObject *mp = (PyDictObject *)d; - PyObject *oldvalue; - Py_ssize_t pos = 0; - PyObject *key; - Py_hash_t hash; - - if (dictresize(mp, Py_SIZE(seq))) { - Py_DECREF(d); - return NULL; - } - - while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { - Py_INCREF(key); - Py_INCREF(value); - if (insertdict(mp, key, hash, value)) { + if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) { + if (PyDict_CheckExact(seq)) { + PyDictObject *mp = (PyDictObject *)d; + PyObject *oldvalue; + Py_ssize_t pos = 0; + PyObject *key; + Py_hash_t hash; + + if (dictresize(mp, Py_SIZE(seq))) { Py_DECREF(d); return NULL; } - } - return d; - } - if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { - PyDictObject *mp = (PyDictObject *)d; - Py_ssize_t pos = 0; - PyObject *key; - Py_hash_t hash; - - if (dictresize(mp, PySet_GET_SIZE(seq))) { - Py_DECREF(d); - return NULL; + while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) { + Py_DECREF(d); + return NULL; + } + } + return d; } + if (PyAnySet_CheckExact(seq)) { + PyDictObject *mp = (PyDictObject *)d; + Py_ssize_t pos = 0; + PyObject *key; + Py_hash_t hash; - while (_PySet_NextEntry(seq, &pos, &key, &hash)) { - Py_INCREF(key); - Py_INCREF(value); - if (insertdict(mp, key, hash, value)) { + if (dictresize(mp, PySet_GET_SIZE(seq))) { Py_DECREF(d); return NULL; } + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) { + Py_DECREF(d); + return NULL; + } + } + return d; } - return d; } it = PyObject_GetIter(seq); |