Skip to content

Commit 9761006

Browse files
authored
Handle KeyboardInterrupt and SystemExit at collection time (#12191)
1 parent 4c5298c commit 9761006

File tree

4 files changed

+36
-1
lines changed

4 files changed

+36
-1
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Andrey Paramonov
3636
Andrzej Klajnert
3737
Andrzej Ostrowski
3838
Andy Freeland
39+
Anita Hammer
3940
Anthon van der Neut
4041
Anthony Shaw
4142
Anthony Sottile

changelog/12191.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Keyboard interrupts and system exits are now properly handled during the test collection.

src/_pytest/runner.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,9 @@ def collect() -> List[Union[Item, Collector]]:
393393

394394
return list(collector.collect())
395395

396-
call = CallInfo.from_call(collect, "collect")
396+
call = CallInfo.from_call(
397+
collect, "collect", reraise=(KeyboardInterrupt, SystemExit)
398+
)
397399
longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None
398400
if not call.excinfo:
399401
outcome: Literal["passed", "skipped", "failed"] = "passed"

testing/test_collection.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import tempfile
88
import textwrap
99
from typing import List
10+
from typing import Type
1011

1112
from _pytest.assertion.util import running_on_ci
1213
from _pytest.config import ExitCode
@@ -1856,3 +1857,33 @@ def test_do_not_collect_symlink_siblings(
18561857
# Ensure we collect it only once if we pass the symlinked directory.
18571858
result = pytester.runpytest(symlink_path, "-sv")
18581859
result.assert_outcomes(passed=1)
1860+
1861+
1862+
@pytest.mark.parametrize(
1863+
"exception_class, msg",
1864+
[
1865+
(KeyboardInterrupt, "*!!! KeyboardInterrupt !!!*"),
1866+
(SystemExit, "INTERNALERROR> SystemExit"),
1867+
],
1868+
)
1869+
def test_respect_system_exceptions(
1870+
pytester: Pytester,
1871+
exception_class: Type[BaseException],
1872+
msg: str,
1873+
):
1874+
head = "Before exception"
1875+
tail = "After exception"
1876+
ensure_file(pytester.path / "test_eggs.py").write_text(
1877+
f"print('{head}')", encoding="UTF-8"
1878+
)
1879+
ensure_file(pytester.path / "test_ham.py").write_text(
1880+
f"raise {exception_class.__name__}()", encoding="UTF-8"
1881+
)
1882+
ensure_file(pytester.path / "test_spam.py").write_text(
1883+
f"print('{tail}')", encoding="UTF-8"
1884+
)
1885+
1886+
result = pytester.runpytest_subprocess("-s")
1887+
result.stdout.fnmatch_lines([f"*{head}*"])
1888+
result.stdout.fnmatch_lines([msg])
1889+
result.stdout.no_fnmatch_line(f"*{tail}*")

0 commit comments

Comments
 (0)