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
UserDict test assumes ordered dict repr #63863
Comments
If you run Lib/test/test_userdict.py enough times, sooner or later it'll produce a spurious error. I wrote a shell script that ran "./python -m test test_userdict" a zillion times; here's a snippet of output from running that script: [...]
1 test OK.
[1/1] test_userdict
1 test OK.
[1/1] test_userdict
1 test OK.
[1/1] test_userdict
test test_userdict failed -- Traceback (most recent call last):
File "/home/larry/src/python/clinic/Lib/test/test_userdict.py", line 48, in test_all
self.assertEqual(repr(u2), repr(d2))
AssertionError: "{'one': 1, 'two': 2}" != "{'two': 2, 'one': 1}"
- {'one': 1, 'two': 2}
+ {'two': 2, 'one': 1} 1 test failed: Line 48 reads as follows: I realize this code is ancient--but it seems to rely on repr of a dict producing consistent output, which is silly and has always been wrong. Raymond, you want to take this? |
In test_set, I fixed the issue by parsing repr() output, sorting items and then compare sorted items :-) |
Well, it sounds a bit weird to me... If you're building the dict always in the same way, intuitively it should always produce the same repr() during the same interpreter session. Do you know why it doesn't? |
I don't know for sure--I haven't stepped through it--but here's an informed guess. It relies on key collision. The first dict is created the normal way. It contains two values, "one" (set to 1) and "two" (set to 2), inserted in that order. The second dict is created by calling dict.update(), passing in the first dict. update() iterates over the keys of the dict's hash table with a simple for(;;) loop, copying the key and value each time. The order is effectively random. The repr() then iterates over the keys using the same simple for(;;) loop, spitting out key=value strings. Let's assume that the keys collide. "one" is inserted first, so it gets its first choice. "two" is inserted second so it must probe. Let's assume that its second choice is a key slot *lower* (nearer to [0]) than "one". Now when we use update(), the for(;;) loop sees "two" first. So "two" gets its first choice, which means "one" must now probe. If "one"'s second choice is a key slot *higher* (further from [0]) than "two", we'll see the behavior. (Why does this only happen sometimes? Because we're using "hash randomization".) |
Ok, I see. The frequency of the errors then depends on the frequency of |
Here is a patch for test_userdict. |
bpo-19664.patch looks good to me. Funny fact: test_repr() of test_dict only test dictionaries with 1 item :) |
New changeset a0ec33b83ba4 by Christian Heimes in branch 'default': |
Thanks Serhiy! Your patch was simple yet elegant. :) |
New changeset b62eb82ca5ef by Christian Heimes in branch 'default': |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: