Skip to content
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

Closed
larryhastings opened this issue Nov 20, 2013 · 10 comments
Closed

UserDict test assumes ordered dict repr #63863

larryhastings opened this issue Nov 20, 2013 · 10 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@larryhastings
Copy link
Contributor

BPO 19664
Nosy @rhettinger, @pitrou, @vstinner, @larryhastings, @tiran, @serhiy-storchaka
Files
  • issue19664.patch
  • 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:

    assignee = 'https://github.com/rhettinger'
    closed_at = <Date 2013-11-22.00:20:06.510>
    created_at = <Date 2013-11-20.17:09:42.355>
    labels = ['type-bug', 'library']
    title = 'UserDict test assumes ordered dict repr'
    updated_at = <Date 2013-11-22.02:36:57.922>
    user = 'https://github.com/larryhastings'

    bugs.python.org fields:

    activity = <Date 2013-11-22.02:36:57.922>
    actor = 'python-dev'
    assignee = 'rhettinger'
    closed = True
    closed_date = <Date 2013-11-22.00:20:06.510>
    closer = 'christian.heimes'
    components = ['Library (Lib)']
    creation = <Date 2013-11-20.17:09:42.355>
    creator = 'larry'
    dependencies = []
    files = ['32759']
    hgrepos = []
    issue_num = 19664
    keywords = ['patch']
    message_count = 10.0
    messages = ['203509', '203514', '203519', '203524', '203525', '203662', '203687', '203703', '203704', '203713']
    nosy_count = 7.0
    nosy_names = ['rhettinger', 'pitrou', 'vstinner', 'larry', 'christian.heimes', 'python-dev', 'serhiy.storchaka']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue19664'
    versions = ['Python 3.4']

    @larryhastings
    Copy link
    Contributor Author

    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:
    test_userdict
    [1/1] test_userdict
    1 test OK.
    [1/1] test_userdict
    1 test OK.
    [...]

    Line 48 reads as follows:
    self.assertEqual(repr(u2), repr(d2))

    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?

    @larryhastings larryhastings added stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error labels Nov 20, 2013
    @vstinner
    Copy link
    Member

    In test_set, I fixed the issue by parsing repr() output, sorting items and then compare sorted items :-)

    @pitrou
    Copy link
    Member

    pitrou commented Nov 20, 2013

    I realize this code is ancient--but it seems to rely on repr of a dict
    producing consistent output, which is silly

    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?

    @larryhastings
    Copy link
    Contributor Author

    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".)

    @pitrou
    Copy link
    Member

    pitrou commented Nov 20, 2013

    I don't know for sure--I haven't stepped through it--but here's an
    informed guess. It relies on key collision.

    Ok, I see. The frequency of the errors then depends on the frequency of
    collisions for two fixed keys and a varying hash seed...

    @rhettinger rhettinger self-assigned this Nov 21, 2013
    @serhiy-storchaka
    Copy link
    Member

    Here is a patch for test_userdict.

    @vstinner
    Copy link
    Member

    bpo-19664.patch looks good to me.

    Funny fact: test_repr() of test_dict only test dictionaries with 1 item :)

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Nov 22, 2013

    New changeset a0ec33b83ba4 by Christian Heimes in branch 'default':
    Issue bpo-19664: test_userdict's repr test no longer depends on the order
    http://hg.python.org/cpython/rev/a0ec33b83ba4

    @tiran
    Copy link
    Member

    tiran commented Nov 22, 2013

    Thanks Serhiy! Your patch was simple yet elegant. :)

    @tiran tiran closed this as completed Nov 22, 2013
    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Nov 22, 2013

    New changeset b62eb82ca5ef by Christian Heimes in branch 'default':
    Issue bpo-19664: fix another flake test_userdict test
    http://hg.python.org/cpython/rev/b62eb82ca5ef

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    6 participants