diff --git a/changelog/5630.improvement.rst b/changelog/5630.improvement.rst new file mode 100644 index 000000000..45d49bdae --- /dev/null +++ b/changelog/5630.improvement.rst @@ -0,0 +1 @@ +Quitting from debuggers is now properly handled in ``doctest`` items. diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index cf886f906..1bd2642ae 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -1,4 +1,5 @@ """ discover and run doctests in modules and test files.""" +import bdb import inspect import platform import sys @@ -7,6 +8,7 @@ import warnings from contextlib import contextmanager import pytest +from _pytest import outcomes from _pytest._code.code import ExceptionInfo from _pytest._code.code import ReprFileLocation from _pytest._code.code import TerminalRepr @@ -155,6 +157,8 @@ def _init_runner_class(): def report_unexpected_exception(self, out, test, example, exc_info): if isinstance(exc_info[1], Skipped): raise exc_info[1] + if isinstance(exc_info[1], bdb.BdbQuit): + outcomes.exit("Quitting debugger") failure = doctest.UnexpectedException(test, example, exc_info) if self.continue_on_failure: out.append(failure) diff --git a/testing/test_pdb.py b/testing/test_pdb.py index 924c2f4af..7d9436313 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -466,7 +466,6 @@ class TestPDB: def test_pdb_interaction_doctest(self, testdir, monkeypatch): p1 = testdir.makepyfile( """ - import pytest def function_1(): ''' >>> i = 0 @@ -485,9 +484,32 @@ class TestPDB: child.sendeof() rest = child.read().decode("utf8") + assert "! _pytest.outcomes.Exit: Quitting debugger !" in rest + assert "BdbQuit" not in rest assert "1 failed" in rest self.flush(child) + def test_doctest_set_trace_quit(self, testdir, monkeypatch): + p1 = testdir.makepyfile( + """ + def function_1(): + ''' + >>> __import__('pdb').set_trace() + ''' + """ + ) + # NOTE: does not use pytest.set_trace, but Python's patched pdb, + # therefore "-s" is required. + child = testdir.spawn_pytest("--doctest-modules --pdb -s %s" % p1) + child.expect("Pdb") + child.sendline("q") + rest = child.read().decode("utf8") + + assert "! _pytest.outcomes.Exit: Quitting debugger !" in rest + assert "= no tests ran in" in rest + assert "BdbQuit" not in rest + assert "UNEXPECTED EXCEPTION" not in rest + def test_pdb_interaction_capturing_twice(self, testdir): p1 = testdir.makepyfile( """