Skip to content

Commit 7ba65a6

Browse files
- added --pytest-args to reduce, to allow passing extra arguments to pytest;
1 parent 4cddf7c commit 7ba65a6

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

src/pytest_cleanslate/reduce.py

+17-10
Original file line numberDiff line numberDiff line change
@@ -199,18 +199,22 @@ def _bisect_items(items: T.List[str], failing: str, fails: T.Callable[[T.List[st
199199
return items
200200

201201

202-
def _reduce_tests(tests_path: Path, tests: T.List[str], failing_test: str, *, trace=None) -> T.List[str]:
202+
def _reduce_tests(tests_path: Path, tests: T.List[str], failing_test: str,
203+
*, trace: bool = False, pytest_args: T.List[str] = ()) -> T.List[str]:
203204
def fails(test_set: T.List[str]):
204-
trial = _run_pytest(tests_path, ('--continue-on-collection-errors',), tests=test_set, trace=trace)
205+
trial = _run_pytest(tests_path, (*pytest_args, '--continue-on-collection-errors'),
206+
tests=test_set, trace=trace)
205207
return trial.get_outcome(failing_test) == 'failed'
206208

207209
return _bisect_items(tests, failing_test, fails)
208210

209211

210212
def _reduce_modules(tests_path: Path, tests: T.List[str], failing_test: str,
211-
modules: T.List[str], failing_module: str, *, trace=None) -> T.List[str]:
213+
modules: T.List[str], failing_module: str,
214+
*, trace: bool = False, pytest_args: T.List[str] = ()) -> T.List[str]:
212215
def fails(module_set: T.List[str]):
213-
trial = _run_pytest(tests_path, ('--continue-on-collection-errors',), tests=tests, modules=module_set, trace=trace)
216+
trial = _run_pytest(tests_path, (*pytest_args, '--continue-on-collection-errors',),
217+
tests=tests, modules=module_set, trace=trace)
214218
return trial.get_outcome(failing_test) == 'failed'
215219

216220
return _bisect_items(modules, failing_module, fails)
@@ -224,6 +228,7 @@ def _parse_args():
224228
ap = argparse.ArgumentParser()
225229
ap.add_argument('--trace', default=False, action=bool_action, help='show pytest outputs, etc.')
226230
ap.add_argument('--save-to', type=Path, help='file where to save results (JSON)')
231+
ap.add_argument('--pytest-args', type=str, default='', help='extra arguments to pass to pytest')
227232
ap.add_argument('--version', action='version',
228233
version=f"%(prog)s v{__version__} (Python {'.'.join(map(str, sys.version_info[:3]))})")
229234
ap.add_argument('tests_path', type=Path, help='tests file or directory')
@@ -233,9 +238,10 @@ def _parse_args():
233238

234239
def main():
235240
args = _parse_args()
241+
pytest_args = args.pytest_args.split()
236242

237243
print("Running tests...", flush=True)
238-
results = _run_pytest(args.tests_path, ('-x',), trace=args.trace)
244+
results = _run_pytest(args.tests_path, (*pytest_args, '-x'), trace=args.trace)
239245

240246
failed = results.get_first_failed()
241247
if failed is None:
@@ -254,14 +260,14 @@ def main():
254260
if args.trace: print()
255261
print(f"Module \"{failed}\"'s collection failed; trying it by itself...", flush=True)
256262
failed_module = failed
257-
solo = _run_pytest(args.tests_path, modules=[failed_module], trace=args.trace)
263+
tests = None
258264
else:
259265
if args.trace: print()
260266
print(f"Test \"{failed}\" failed; trying it by itself...", flush=True)
261267
failed_module = results.get_module(failed)
268+
tests = [failed]
262269

263-
solo = _run_pytest(args.tests_path, modules=[failed_module], tests=[failed], trace=args.trace)
264-
270+
solo = _run_pytest(args.tests_path, pytest_args, modules=[failed_module], tests=tests, trace=args.trace)
265271
if solo.get_outcome(failed) != 'passed':
266272
print("That also fails by itself!", flush=True)
267273
if args.save_to:
@@ -279,13 +285,14 @@ def main():
279285

280286
if args.trace: print()
281287
print("Trying to reduce test set...", flush=True)
282-
tests = _reduce_tests(args.tests_path, tests, failed, trace=args.trace)
288+
tests = _reduce_tests(args.tests_path, tests, failed, trace=args.trace, pytest_args=pytest_args)
283289

284290
if args.trace: print()
285291
print("Trying to reduce module set...", flush=True)
286292

287293
modules = [m for m in results.get_modules() if m != failed_module]
288-
modules = _reduce_modules(args.tests_path, tests if is_module else tests + [failed], failed, modules, failed_module, trace=args.trace)
294+
modules = _reduce_modules(args.tests_path, tests if is_module else tests + [failed], failed,
295+
modules, failed_module, trace=args.trace, pytest_args=pytest_args)
289296

290297
if args.trace: print()
291298
print("Reduced failure set:")

tests/test_reduce.py

+23
Original file line numberDiff line numberDiff line change
@@ -218,3 +218,26 @@ def test_nothing():
218218
assert reduction['failed'] == failing
219219
assert reduction['modules'] == [get_test_module(polluter)]
220220
assert reduction['tests'] == []
221+
222+
223+
@pytest.mark.parametrize("pollute_in_collect, fail_collect", [[False, False], [True, False], [True, True]])
224+
def test_reduce_pytest_args(tests_dir, pollute_in_collect, fail_collect):
225+
failing, polluter, tests = make_polluted_suite(tests_dir, fail_collect=fail_collect, pollute_in_collect=pollute_in_collect)
226+
227+
(tests_dir / "conftest.py").write_text(dedent("""\
228+
if read, this breaks everything
229+
"""))
230+
231+
reduction_file = tests_dir.parent / "reduction.json"
232+
233+
p = subprocess.run([sys.executable, '-m', 'pytest_cleanslate.reduce',
234+
'--save-to', reduction_file, '--trace',
235+
'--pytest-args=--noconftest', tests_dir], check=False)
236+
assert p.returncode == 0
237+
238+
with reduction_file.open("r") as f:
239+
reduction = json.load(f)
240+
241+
assert reduction['failed'] == failing
242+
assert reduction['modules'] == [get_test_module(polluter)]
243+
assert reduction['tests'] == [] if pollute_in_collect else [polluter]

0 commit comments

Comments
 (0)