Skip to content

Calling assertEquals for moderately long list takes too long #63416

Closed as duplicate

Description

@JacekBzdak
BPO 19217
Nosy @terryjreedy, @gpshead, @pfmoore, @pitrou, @rbtcollins, @tjguk, @ezio-melotti, @voidspace, @ambv, @zware, @serhiy-storchaka, @zooba, @elenaoat, @nnja, @ilevkivskyi, @treyhunner, @elafontaine, @eamanu, @tirkarthi, @jdevries3133
PRs
  • Fix bpo-19217: Calling assertEquals for moderately long list takes too long #10034
  • Fix bpo-19217: Calling assertEquals for moderately long list takes too long #11204
  • gh-63416: Speed up assertEqual on long sequences #27434
  • Files
  • unittest_scse.py: SCSE
  • issue19217.diff
  • issue19217-1.diff
  • issue19217-2.diff
  • issue19217-3.diff
  • issue19217-alt.diff
  • issue19217-profile.txt: profile output of the test case
  • cpython-issue19217.diff: Use difflib.unified_diff instead of ndiff
  • unittest_unified_diff.patch
  • unified_diff.py
  • issue_19217.diff
  • 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/ezio-melotti'
    closed_at = None
    created_at = <Date 2013-10-10.13:04:46.624>
    labels = ['3.11', 'library', 'performance']
    title = 'Calling assertEquals for moderately long list takes too long'
    updated_at = <Date 2022-03-04.11:49:12.121>
    user = 'https://bugs.python.org/JacekBzdak'

    bugs.python.org fields:

    activity = <Date 2022-03-04.11:49:12.121>
    actor = 'AlexWaygood'
    assignee = 'ezio.melotti'
    closed = False
    closed_date = None
    closer = None
    components = ['Library (Lib)']
    creation = <Date 2013-10-10.13:04:46.624>
    creator = 'Jacek.Bzdak'
    dependencies = []
    files = ['32033', '32105', '36144', '36292', '36295', '36330', '37001', '41824', '46573', '46574', '47921']
    hgrepos = []
    issue_num = 19217
    keywords = ['patch', 'needs review']
    message_count = 30.0
    messages = ['199383', '199384', '199466', '199833', '199855', '200770', '200827', '216480', '217426', '217563', '224193', '224965', '224983', '225126', '225130', '225132', '225134', '229858', '229910', '259674', '261712', '287264', '287284', '329655', '329657', '370632', '398008', '398198', '398440', '405890']
    nosy_count = 25.0
    nosy_names = ['terry.reedy', 'gregory.p.smith', 'paul.moore', 'pitrou', 'rbcollins', 'tim.golden', 'ezio.melotti', 'michael.foord', 'lukasz.langa', 'zach.ware', 'serhiy.storchaka', 'Jacek.Bzdak', 'steve.dower', 'Ankur.Ankan', 'Elena.Oat', 'nnja', 'ankurankan', 'Puneeth.Chaganti', 'levkivskyi', 'Chris AtLee', 'trey', 'Eric Lafontaine', 'eamanu', 'xtreak', 'jack__d']
    pr_nums = ['10034', '11204', '27434']
    priority = 'high'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'resource usage'
    url = 'https://bugs.python.org/issue19217'
    versions = ['Python 3.11']

    Activity

    1. JacekBzdak commented on Oct 10, 2013

      JacekBzdakmannequin
      MannequinAuthor

      Call to assertEquals(list1, list2) does not finish (takes more than couple of minutes), for lists that containt 10000 elements if all list elements are different. The same call in python2.6 finishes instanteneously.

      This occours even if error message is truncated using maxDiff.

    2. added
      stdlibStandard Library Python modules in the Lib/ directory
      performancePerformance or resource usage
      on Oct 10, 2013
    3. JacekBzdak commented on Oct 10, 2013

      JacekBzdakmannequin
      MannequinAuthor

      I have attached a simple test case.

    4. voidspace commented on Oct 11, 2013

      @voidspace
      Contributor

      Ouch. Looking.

    5. ezio-melotti commented on Oct 14, 2013

      @ezio-melotti
      Member

      Here's a proof of concept to fix the issue (still lacks tests and breaks one existing test).

      The problem is that assertSequenceEqual computes the diff regardless of the size of the sequences, and then truncates it if it's too long. Producing the diff takes time, so checking the size of the sequences and skip the diff if they are too long solves the problem.

      In the patch I used an hardcoded and arbitrary value of 30 elements -- the other attributes like maxDiff and _diffThreshold can't be used here.
      The value is so low because if the sequence doesn't fit in one line, the output will list one element per line, resulting in 30+ lines of output which is not very readable IMHO. Also note that regardless of the this diff, the error message indicates what is the position of the first element that differs.
      The threshold value I picked could be moved to a _seqDiffThreshold (and possibly _diffThreshold can be renamed to _strDiffThreshold).

      This issue is related to bpo-11763. All other methods should be checked for similar issues.

    6. serhiy-storchaka commented on Oct 14, 2013

      @serhiy-storchaka
      Member

      Perhaps a combination of len(pprint.pformat(seq1).splitlines()) and len(pprint.pformat(seq2).splitlines()) (minimum, maximum or production) is better metric?

    7. JacekBzdak commented on Oct 21, 2013

      JacekBzdakmannequin
      MannequinAuthor

      The patch works for me, thanks Ezio!

    8. voidspace commented on Oct 21, 2013

      @voidspace
      Contributor

      pprint is also likely to have performance issues. I agree with Ezio that a diff consisting of more than 30(x2) lines is not likely to be directly useful anyway.

      A test for the changed behaviour would be nice.

    9. nnja commented on Apr 16, 2014

      @nnja
      Contributor

      The cause of this has been identified as a bug in libdiff.compare(). See bpo-21253 for more information.

    10. pitrou commented on Apr 28, 2014

      @pitrou
      Member

      Ezio, do you intend to add a test to your patch?

    11. ezio-melotti commented on Apr 30, 2014

      @ezio-melotti
      Member

      I don't think I will have time for this for a while, so if anyone wants to provide tests they are welcomed to do it.
      The related bpo-11763 already has some tests, so those might be adapted for this issue.

    12. 33 remaining items

    13. jdevries3133 commented on Jul 28, 2021

      jdevries3133mannequin
      Mannequin

      I'm going to go ahead and submit my PR under the assumption that Lukasz will probably prefer to actually be able to review it when he takes a look at this, and additionally we haven't heard from @eamanu.

      @eamanu, I'll close it if you would like to continue; just let me know!

    14. jdevries3133 commented on Nov 7, 2021

      jdevries3133mannequin
      Mannequin

      Hey all, I'm putting a ping on this issue. I think my fix is ready to merge, see python/issues-test-cpython#27434. Thanks for all the feedback on the PR so far!

    15. transferred this issue fromon Apr 10, 2022
    16. added
      3.12only security fixes
      and removed
      3.11only security fixes
      on Sep 11, 2022
    17. Lenormju commented on Jul 18, 2026

      @Lenormju
      Contributor

      Seems like the PR #27434 was closed because performance is good enough now, the underlying perf issues having been merged over the time. Could this be closed now ?

    18. vstinner commented on Jul 18, 2026

      @vstinner
      Member

      Using attached unittest_scse.py script, I confirm that the issue has been fixed. I ran git bisect with this script and I found one change.

      This issue has been fixed in Python 3.14 by commit de19694:

      commit de19694cfbcaa1c85c3a4b7184a24ff21b1c0919
      Author: Tim Peters <tim.peters@gmail.com>
      Date:   Fri May 24 22:08:21 2024 -0500
      
          gh-119105: Differ.compare is too slow [for degenerate cases] (#119492)
          
          ``_fancy_replace()`` is no longer recursive. and a single call does a worst-case linear number of ratio() computations instead of quadratic. This renders toothless a universe of pathological cases. Some inputs may produce different output, but that's rare, and I didn't find a case where the final diff appeared to be of materially worse quality. To the contrary, by refusing to even consider synching on lines "far apart", there was more easy-to-digest locality in the output.
      
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    Labels

    3.12only security fixesperformancePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directory

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions