-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-34320: Fix dict(o) didn't copy order of dict subclass #8624
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to add tests for PEP 468 and PEP 520. These tests should be backported to 3.6, but the test for the dict constructor can not.
Objects/dictobject.c
Outdated
@@ -2379,7 +2379,7 @@ dict_merge(PyObject *a, PyObject *b, int override) | |||
return -1; | |||
} | |||
mp = (PyDictObject*)a; | |||
if (PyDict_Check(b)) { | |||
if (PyDict_CheckExact(b)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be too restrictive. Most dict subclasses don't change the order. Maybe check also that __iter__
is not overridden?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean, "Maybe check instead", right? So something like the following.
if (PyDict_Check(b) && Py_TYPE(b)->tp_iter == PyDict_Type.tp_iter) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the tp_iter checks seems like the most reasonable way to go. That would preserve the fast conversion speed of defaultdict.
Please add tests. |
@serhiy-storchaka Which type of test? |
Tests for for PEP 468 and PEP 520. |
af63eda
to
253f5db
Compare
Lib/test/test_ordered_dict.py
Outdated
# Dict preserves order by language spec from 3.7. | ||
# Dict preserves order by implementation from 3.6. | ||
if sys.version_info < (3, 7): | ||
test_dict_copy_order = support.cpython_only(test_dict_copy_order) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 3.7+ this is not needed. And I think that in <3.7 this test should be backported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, what do you mean concretely?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are ran with concrete Python version. sys.version_info
is a constant in every branch. In branches master and 3.7 these two lines should be removed. In branch 3.6 the decorator should be added unconditionally. But the backport to 3.6 needs editing in any case (only the test should be backported), so I don't think this will add additional work.
Perhaps there are better places for tests for PEP 468 and PEP 520. I would try to break the order of all kwargs dicts and class dicts and see what tests will fail. |
I have made |
FYI, PEP 520 is reverted because of dict preserves order. |
We missed 3.7.1, maybe. May I add comment like "# TODO: Move this test to better place" and merge this? |
Would be nice to mention PEP 468 and 520 in comments for corresponding tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @methane!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside from moving the tests you already have, there should be at least 3 more tests:
- with a
metaclass.__prepare__
that returns anOrderedDict
(see https://bugs.python.org/issue34320#msg325898) -- this would be next to either other tests related to__prepare__()
or other tests related totype()
dict(obj)
whereobj
is an instance of some non-OrderedDict
subclass ofdict
without a custom__iter__
-- this would be intest_dict.py
dict(obj)
whereobj
is an instance of some subclass ofdict
with a custom__iter__
-- this would be intest_dict.py
Lib/test/test_ordered_dict.py
Outdated
@@ -650,6 +650,41 @@ def test_free_after_iterating(self): | |||
support.check_free_after_iterating(self, lambda d: iter(d.values()), self.OrderedDict) | |||
support.check_free_after_iterating(self, lambda d: iter(d.items()), self.OrderedDict) | |||
|
|||
# TODO: This test is relating to PEP 468. | |||
# Move this test to somewhere more appropriate. | |||
def test_kwargs_order(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is about kwargs
ordering rather than OrderedDict
, so I'd expect it to be next to other tests for kwargs
, not here in test_ordered_dict.py
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but problem is I can't find other tests for kwargs
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added new test class for this, in test_call.py
Lib/test/test_ordered_dict.py
Outdated
self.assertIsInstance(res, dict) | ||
self.assertEqual(list(res.items()), expected) | ||
|
||
# TODO: This test is relating to PEP 520. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not specific to PEP 520, which only relates directly to the class definition namespace. So you should drop this comment.
Lib/test/test_ordered_dict.py
Outdated
|
||
# TODO: This test is relating to PEP 520. | ||
# Move this test to somewhere more appropriate. | ||
def test_type_namespace_order(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test should be next to other tests of the type()
builtin.
Lib/test/test_ordered_dict.py
Outdated
C = type('C', (), od) | ||
self.assertEqual(list(C.__dict__.items())[:2], [('b', 2), ('a', 1)]) | ||
|
||
def test_dict_copy_order(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test should be in test_dict.py
.
When you're done making the requested changes, leave the comment: |
Thank you for your suggestions @ericsnowcurrently. They all LGTM. |
f117479
to
603bc6c
Compare
603bc6c
to
ee8696d
Compare
Thanks @methane for the PR 🌮🎉.. I'm working now to backport this PR to: 3.6, 3.7. |
GH-9582 is a backport of this pull request to the 3.7 branch. |
) When dict subclass overrides order (`__iter__()`, `keys()`, and `items()`), `dict(o)` should use it instead of dict ordering. https://bugs.python.org/issue34320 (cherry picked from commit 2aaf98c) Co-authored-by: INADA Naoki <methane@users.noreply.github.com>
GH-9583 is a backport of this pull request to the 3.6 branch. |
) When dict subclass overrides order (`__iter__()`, `keys()`, and `items()`), `dict(o)` should use it instead of dict ordering. https://bugs.python.org/issue34320 (cherry picked from commit 2aaf98c) Co-authored-by: INADA Naoki <methane@users.noreply.github.com>
When dict subclass overrides order (`__iter__()`, `keys()`, and `items()`), `dict(o)` should use it instead of dict ordering. https://bugs.python.org/issue34320 (cherry picked from commit 2aaf98c) Co-authored-by: INADA Naoki <methane@users.noreply.github.com>
) (GH-9583) When dict subclass overrides order (`__iter__()`, `keys()`, and `items()`), `dict(o)` should use it instead of dict ordering. https://bugs.python.org/issue34320 (cherry picked from commit 2aaf98c) Co-authored-by: INADA Naoki <methane@users.noreply.github.com> https://bugs.python.org/issue34320
When dict subclass overrides order (
__iter__()
,keys()
, anditems()
),dict(o)
should use it instead of dict ordering.
https://bugs.python.org/issue34320