From d4879c7afbf17192565926c3acb7dd633fd588f2 Mon Sep 17 00:00:00 2001 From: Seth Junot Date: Sun, 15 Dec 2019 18:58:08 -0800 Subject: [PATCH] Optimized renaming of test parameter ids While using pytest-repeat, I noticed the previous implementation is slow for a large number of duplicate test ids. To optimize, this commit reduces the amount of data copied and avoids using `in` with List (unhashable type, and therefore is very slow for many elements). --- AUTHORS | 1 + changelog/6350.trivial.rst | 1 + src/_pytest/python.py | 26 ++++++++++++++++++-------- 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 changelog/6350.trivial.rst diff --git a/AUTHORS b/AUTHORS index cc9b14be336..6288f8c1b02 100644 --- a/AUTHORS +++ b/AUTHORS @@ -235,6 +235,7 @@ Samuele Pedroni Sankt Petersbug Segev Finer Serhii Mozghovyi +Seth Junot Simon Gomizelj Skylar Downes Srinivas Reddy Thatiparthy diff --git a/changelog/6350.trivial.rst b/changelog/6350.trivial.rst new file mode 100644 index 00000000000..c43fb42679c --- /dev/null +++ b/changelog/6350.trivial.rst @@ -0,0 +1 @@ +Optimized automatic renaming of test parameter IDs. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index d787638c9f1..bc35ccf5f10 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -6,6 +6,7 @@ import sys import warnings from collections import Counter +from collections import defaultdict from collections.abc import Sequence from functools import partial from textwrap import dedent @@ -1190,14 +1191,23 @@ def idmaker(argnames, parametersets, idfn=None, ids=None, config=None, item=None _idvalset(valindex, parameterset, argnames, idfn, ids, config=config, item=item) for valindex, parameterset in enumerate(parametersets) ] - if len(set(ids)) != len(ids): - # The ids are not unique - duplicates = [testid for testid in ids if ids.count(testid) > 1] - counters = Counter() - for index, testid in enumerate(ids): - if testid in duplicates: - ids[index] = testid + str(counters[testid]) - counters[testid] += 1 + + # All IDs must be unique! + unique_ids = set(ids) + if len(unique_ids) != len(ids): + + # Record the number of occurrences of each test ID + test_id_counts = Counter(ids) + + # Map the test ID to its next suffix + test_id_suffixes = defaultdict(int) + + # Suffix non-unique IDs to make them unique + for index, test_id in enumerate(ids): + if test_id_counts[test_id] > 1: + ids[index] = "{}{}".format(test_id, test_id_suffixes[test_id]) + test_id_suffixes[test_id] += 1 + return ids