Skip to content

Commit 253f5db

Browse files
committed
bpo-34320: Fix dict(od) didn't copy order
1 parent 2ebd381 commit 253f5db

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

Lib/test/test_ordered_dict.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,43 @@ def test_free_after_iterating(self):
650650
support.check_free_after_iterating(self, lambda d: iter(d.values()), self.OrderedDict)
651651
support.check_free_after_iterating(self, lambda d: iter(d.items()), self.OrderedDict)
652652

653+
def test_kwargs_order(self):
654+
# bpo-34320
655+
od = self.OrderedDict([('a', 1), ('b', 2)])
656+
od.move_to_end('a')
657+
expected = list(od.items())
658+
659+
def fn(**kw):
660+
return kw
661+
662+
res = fn(**od)
663+
self.assertIsInstance(res, dict)
664+
self.assertEqual(list(res.items()), expected)
665+
666+
def test_type_namespace_order(self):
667+
# bpo-34320
668+
od = self.OrderedDict([('a', 1), ('b', 2)])
669+
od.move_to_end('a')
670+
expected = list(od.items())
671+
672+
C = type('C', (), od)
673+
self.assertEqual(list(C.__dict__.items())[:2], [('b', 2), ('a', 1)])
674+
675+
def test_dict_copy_order(self):
676+
# Issue 34320
677+
od = self.OrderedDict([('a', 1), ('b', 2)])
678+
od.move_to_end('a')
679+
expected = list(od.items())
680+
681+
copy = dict(od)
682+
self.assertEqual(list(copy.items()), expected)
683+
684+
# Namespace preserves order by language spec from 3.6.
685+
# Dict preserves order by language spec from 3.7.
686+
# Dict preserves order by implementation from 3.6.
687+
if sys.version_info < (3, 7):
688+
test_dict_copy_order = support.cpython_only(test_dict_copy_order)
689+
653690

654691
class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
655692

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``dict(od)`` didn't copy iteration order of OrderedDict.

Objects/dictobject.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key,
235235

236236
static int dictresize(PyDictObject *mp, Py_ssize_t minused);
237237

238+
static PyObject* dict_iter(PyDictObject *dict);
239+
238240
/*Global counter used to set ma_version_tag field of dictionary.
239241
* It is incremented each time that a dictionary is created and each
240242
* time that a dictionary is modified. */
@@ -2379,7 +2381,7 @@ dict_merge(PyObject *a, PyObject *b, int override)
23792381
return -1;
23802382
}
23812383
mp = (PyDictObject*)a;
2382-
if (PyDict_Check(b)) {
2384+
if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) {
23832385
other = (PyDictObject*)b;
23842386
if (other == mp || other->ma_used == 0)
23852387
/* a.update(a) or a.update({}); nothing to do */

0 commit comments

Comments
 (0)