diff --git a/changelog/4292.feature.rst b/changelog/4292.feature.rst new file mode 100644 index 00000000000..27d113ba069 --- /dev/null +++ b/changelog/4292.feature.rst @@ -0,0 +1 @@ +``pytest.outcomes.Exit`` is derived from ``SystemExit`` instead of ``KeyboardInterrupt``. diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 08490f03aa6..d0d826bb653 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -205,7 +205,7 @@ def wrap_session(config, doit): raise except Failed: session.exitstatus = EXIT_TESTSFAILED - except KeyboardInterrupt: + except (KeyboardInterrupt, exit.Exception): excinfo = _pytest._code.ExceptionInfo.from_current() exitstatus = EXIT_INTERRUPTED if initstate <= 2 and isinstance(excinfo.value, exit.Exception): diff --git a/src/_pytest/outcomes.py b/src/_pytest/outcomes.py index cd08c0d48e4..714be308834 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -49,13 +49,13 @@ class Failed(OutcomeException): __module__ = "builtins" -class Exit(KeyboardInterrupt): +class Exit(SystemExit): """ raised for immediate program exits (no tracebacks/summaries)""" def __init__(self, msg="unknown reason", returncode=None): self.msg = msg self.returncode = returncode - KeyboardInterrupt.__init__(self, msg) + SystemExit.__init__(self, msg) # exposed helper methods @@ -63,7 +63,7 @@ def __init__(self, msg="unknown reason", returncode=None): def exit(msg, returncode=None): """ - Exit testing process as if KeyboardInterrupt was triggered. + Exit testing process as if SystemExit was triggered. :param str msg: message to display upon exit. :param int returncode: return code to be used when exiting pytest. diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index 27f244a80e0..538e13403a7 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -15,6 +15,7 @@ from .reports import CollectReport from .reports import TestReport from _pytest._code.code import ExceptionInfo +from _pytest.outcomes import Exit from _pytest.outcomes import skip from _pytest.outcomes import Skipped from _pytest.outcomes import TEST_OUTCOME @@ -190,10 +191,11 @@ def check_interactive_exception(call, report): def call_runtest_hook(item, when, **kwds): hookname = "pytest_runtest_" + when ihook = getattr(item.ihook, hookname) + reraise = (Exit,) + if not item.config.getvalue("usepdb"): + reraise += (KeyboardInterrupt,) return CallInfo.from_call( - lambda: ihook(item=item, **kwds), - when=when, - reraise=KeyboardInterrupt if not item.config.getvalue("usepdb") else (), + lambda: ihook(item=item, **kwds), when=when, reraise=reraise ) diff --git a/testing/test_runner.py b/testing/test_runner.py index 916c2ea4ae3..ae129d06d27 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -553,7 +553,7 @@ def test_outcomeexception_passes_except_Exception(): def test_pytest_exit(): with pytest.raises(pytest.exit.Exception) as excinfo: pytest.exit("hello") - assert excinfo.errisinstance(KeyboardInterrupt) + assert excinfo.errisinstance(pytest.exit.Exception) def test_pytest_fail():