Skip to content

Commit ab6aef1

Browse files
committed
feature: default behavior now is to ignore duplicate paths specified from the command line. Use --keep-duplicates to retain duplicate paths.
1 parent a24146d commit ab6aef1

File tree

7 files changed

+102
-3
lines changed

7 files changed

+102
-3
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Punyashloka Biswal
9595
Quentin Pradet
9696
Ralf Schmitt
9797
Raphael Pierzina
98+
Roberto Polli
9899
Romain Dorgueil
99100
Roman Bolshakov
100101
Ronny Pfannschmidt

CHANGELOG.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,11 @@ time or change existing behaviors in order to make them less surprising/more use
120120
fixtures and reports them;
121121
+ ``--setup-show``: performs normal test execution and additionally shows
122122
setup and teardown of fixtures;
123+
+ ``--keep-duplicates``: default behavior is now to ignore duplicate paths, you can
124+
retain the old behavior and running multiple times the tests
125+
using the ``--keep-duplicates`` cli argument `#1609`_;
123126

124-
Thanks `@d6e`_, `@kvas-it`_, `@sallner`_ and `@omarkohl`_ for the PRs.
127+
Thanks `@d6e`_, `@kvas-it`_, `@sallner`_, `@ioggstream`_ and `@omarkohl`_ for the PRs.
125128

126129
* New CLI flag ``--override-ini``/``-o``: overrides values from the ini file.
127130
For example: ``"-o xfail_strict=True"``'.
@@ -524,6 +527,7 @@ time or change existing behaviors in order to make them less surprising/more use
524527

525528
.. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing
526529

530+
.. _#1609: https://github.com/pytest-dev/pytest/issues/1609
527531
.. _#1422: https://github.com/pytest-dev/pytest/issues/1422
528532
.. _#1379: https://github.com/pytest-dev/pytest/issues/1379
529533
.. _#1366: https://github.com/pytest-dev/pytest/issues/1366
@@ -549,6 +553,7 @@ time or change existing behaviors in order to make them less surprising/more use
549553
.. _@rabbbit: https://github.com/rabbbit
550554
.. _@hackebrot: https://github.com/hackebrot
551555
.. _@pquentin: https://github.com/pquentin
556+
.. _@ioggstream: https://github.com/ioggstream
552557

553558
2.8.7
554559
=====

_pytest/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ def __init__(self):
155155
self._conftestpath2mod = {}
156156
self._confcutdir = None
157157
self._noconftest = False
158+
self._duplicatepaths = set()
158159

159160
self.add_hookspecs(_pytest.hookspec)
160161
self.register(self)

_pytest/main.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ def pytest_addoption(parser):
6363
group.addoption('--noconftest', action="store_true",
6464
dest="noconftest", default=False,
6565
help="Don't load any conftest.py files.")
66+
group.addoption('--keepduplicates', '--keep-duplicates', action="store_true",
67+
dest="keepduplicates", default=False,
68+
help="Skip duplicate tests.")
6669

6770
group = parser.getgroup("debugconfig",
6871
"test session debugging and configuration")
@@ -154,7 +157,25 @@ def pytest_ignore_collect(path, config):
154157
excludeopt = config.getoption("ignore")
155158
if excludeopt:
156159
ignore_paths.extend([py.path.local(x) for x in excludeopt])
157-
return path in ignore_paths
160+
161+
if path in ignore_paths:
162+
return True
163+
164+
# Skip duplicate paths.
165+
# TODO: is this called when specifying direct filenames
166+
# from command lines, eg.
167+
# py.test test_a.py test_b.py
168+
keepduplicates = config.getoption("keepduplicates")
169+
duplicate_paths = config.pluginmanager._duplicatepaths
170+
if not keepduplicates:
171+
if path in duplicate_paths:
172+
# TODO should we log this?
173+
return True
174+
else:
175+
duplicate_paths.add(path)
176+
177+
return False
178+
158179

159180
class FSHookProxy:
160181
def __init__(self, fspath, pm, remove_mods):

doc/en/example/pythoncollection.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,40 @@ you will see that ``pytest`` only collects test-modules, which do not match the
4040
======= 5 passed in 0.02 seconds =======
4141

4242

43+
Keeping duplicate paths specified from command line
44+
----------------------------------------------------
45+
46+
Default behavior of ``pytest`` is to ignore duplicate paths specified from the command line.
47+
Example::
48+
49+
py.test path_a path_a
50+
51+
...
52+
collected 1 item
53+
...
54+
55+
Just collect tests once.
56+
57+
To collect duplicate tests, use the ``--keep-duplicates`` option on the cli.
58+
Example::
59+
60+
py.test --keep-duplicates path_a path_a
61+
62+
...
63+
collected 2 items
64+
...
65+
66+
As the collector just works on directories, if you specify twice a single test file, ``pytest`` will
67+
still collect it twice, no matter if the ``--keep-duplicates`` is not specified.
68+
Example::
69+
70+
py.test test_a.py test_a.py
71+
72+
...
73+
collected 2 items
74+
...
75+
76+
4377
Changing directory recursion
4478
-----------------------------------------------------
4579

testing/python/collect.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,3 +1213,40 @@ def test_syntax_error_with_non_ascii_chars(testdir):
12131213
'*SyntaxError*',
12141214
'*1 error in*',
12151215
])
1216+
1217+
1218+
def test_skip_duplicates_by_default(testdir):
1219+
"""Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609)
1220+
1221+
Ignore duplicate directories.
1222+
"""
1223+
a = testdir.mkdir("a")
1224+
fh = a.join("test_a.py")
1225+
fh.write(_pytest._code.Source("""
1226+
import pytest
1227+
def test_real():
1228+
pass
1229+
"""))
1230+
result = testdir.runpytest(a.strpath, a.strpath)
1231+
result.stdout.fnmatch_lines([
1232+
'*collected 1 item*',
1233+
])
1234+
1235+
1236+
1237+
def test_keep_duplicates(testdir):
1238+
"""Test for issue https://github.com/pytest-dev/pytest/issues/1609 (#1609)
1239+
1240+
Use --keep-duplicates to collect tests from duplicate directories.
1241+
"""
1242+
a = testdir.mkdir("a")
1243+
fh = a.join("test_a.py")
1244+
fh.write(_pytest._code.Source("""
1245+
import pytest
1246+
def test_real():
1247+
pass
1248+
"""))
1249+
result = testdir.runpytest("--keep-duplicates", a.strpath, a.strpath)
1250+
result.stdout.fnmatch_lines([
1251+
'*collected 2 item*',
1252+
])

testing/python/metafunc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ def pytest_generate_tests(metafunc):
973973
"""))
974974
sub1.join("test_in_sub1.py").write("def test_1(): pass")
975975
sub2.join("test_in_sub2.py").write("def test_2(): pass")
976-
result = testdir.runpytest("-v", "-s", sub1, sub2, sub1)
976+
result = testdir.runpytest("--keep-duplicates", "-v", "-s", sub1, sub2, sub1)
977977
result.assert_outcomes(passed=3)
978978

979979
def test_generate_same_function_names_issue403(self, testdir):

0 commit comments

Comments
 (0)