diff --git a/_pytest/debugging.py b/_pytest/debugging.py index 43472f23bb3..fada117e5dc 100644 --- a/_pytest/debugging.py +++ b/_pytest/debugging.py @@ -87,15 +87,16 @@ def _enter_pdb(node, excinfo, rep): tw = node.config.pluginmanager.getplugin("terminalreporter")._tw tw.line() - captured_stdout = rep.capstdout - if len(captured_stdout) > 0: - tw.sep(">", "captured stdout") - tw.line(captured_stdout) - - captured_stderr = rep.capstderr - if len(captured_stderr) > 0: - tw.sep(">", "captured stderr") - tw.line(captured_stderr) + showcapture = node.config.option.showcapture + + for sectionname, content in (('stdout', rep.capstdout), + ('stderr', rep.capstderr), + ('log', rep.caplog)): + if showcapture in (sectionname, 'all') and content: + tw.sep(">", "captured " + sectionname) + if content[-1:] == "\n": + content = content[:-1] + tw.line(content) tw.sep(">", "traceback") rep.toterminal(tw) diff --git a/_pytest/terminal.py b/_pytest/terminal.py index 69d4ab8add1..55a632b22f7 100644 --- a/_pytest/terminal.py +++ b/_pytest/terminal.py @@ -44,9 +44,9 @@ def pytest_addoption(parser): help="traceback print mode (auto/long/short/line/native/no).") group._addoption('--show-capture', action="store", dest="showcapture", - choices=['no', 'stdout', 'stderr', 'both'], default='both', - help="Controls how captured stdout/stderr is shown on failed tests. " - "Default is 'both'.") + choices=['no', 'stdout', 'stderr', 'log', 'all'], default='all', + help="Controls how captured stdout/stderr/log is shown on failed tests. " + "Default is 'all'.") group._addoption('--fulltrace', '--full-trace', action="store_true", default=False, help="don't cut any tracebacks (default is to cut).") @@ -630,12 +630,12 @@ def summary_errors(self): def _outrep_summary(self, rep): rep.toterminal(self._tw) - if self.config.option.showcapture == 'no': + showcapture = self.config.option.showcapture + if showcapture == 'no': return for secname, content in rep.sections: - if self.config.option.showcapture != 'both': - if not (self.config.option.showcapture in secname): - continue + if showcapture != 'all' and showcapture not in secname: + continue self._tw.sep("-", secname) if content[-1:] == "\n": content = content[:-1] diff --git a/changelog/1478.feature b/changelog/1478.feature index de6bd311890..defc79b9b65 100644 --- a/changelog/1478.feature +++ b/changelog/1478.feature @@ -1 +1 @@ -New ``--show-capture`` command-line option that allows to specify how to display captured output when tests fail: ``no``, ``stdout``, ``stderr`` or ``both`` (the default). \ No newline at end of file +New ``--show-capture`` command-line option that allows to specify how to display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default). diff --git a/changelog/3204.feature b/changelog/3204.feature new file mode 100644 index 00000000000..8ab129a12c9 --- /dev/null +++ b/changelog/3204.feature @@ -0,0 +1 @@ +Captured logs are printed before entering pdb. diff --git a/doc/en/logging.rst b/doc/en/logging.rst index 82119043b01..ad59be83f20 100644 --- a/doc/en/logging.rst +++ b/doc/en/logging.rst @@ -50,26 +50,10 @@ These options can also be customized through ``pytest.ini`` file: log_format = %(asctime)s %(levelname)s %(message)s log_date_format = %Y-%m-%d %H:%M:%S -Further it is possible to disable reporting logs on failed tests completely -with:: +Further it is possible to disable reporting of captured content (stdout, +stderr and logs) on failed tests completely with:: - pytest --no-print-logs - -Or in the ``pytest.ini`` file: - -.. code-block:: ini - - [pytest] - log_print = False - - -Shows failed tests in the normal manner as no logs were captured:: - - ----------------------- Captured stdout call ---------------------- - text going to stdout - ----------------------- Captured stderr call ---------------------- - text going to stderr - ==================== 2 failed in 0.02 seconds ===================== + pytest --show-capture=no caplog fixture diff --git a/testing/test_pdb.py b/testing/test_pdb.py index d882c2cf6dc..fa3d86d314c 100644 --- a/testing/test_pdb.py +++ b/testing/test_pdb.py @@ -187,6 +187,24 @@ def test_1(): assert "captured stderr" not in output self.flush(child) + @pytest.mark.parametrize('showcapture', ['all', 'no', 'log']) + def test_pdb_print_captured_logs(self, testdir, showcapture): + p1 = testdir.makepyfile(""" + def test_1(): + import logging + logging.warn("get " + "rekt") + assert False + """) + child = testdir.spawn_pytest("--show-capture=%s --pdb %s" % (showcapture, p1)) + if showcapture in ('all', 'log'): + child.expect("captured log") + child.expect("get rekt") + child.expect("(Pdb)") + child.sendeof() + rest = child.read().decode("utf8") + assert "1 failed" in rest + self.flush(child) + def test_pdb_interaction_exception(self, testdir): p1 = testdir.makepyfile(""" import pytest diff --git a/testing/test_terminal.py b/testing/test_terminal.py index f23dffe2524..b3ea0170969 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -851,31 +851,47 @@ def pytest_report_header(config, startdir): def test_show_capture(self, testdir): testdir.makepyfile(""" import sys + import logging def test_one(): sys.stdout.write('!This is stdout!') sys.stderr.write('!This is stderr!') + logging.warning('!This is a warning log msg!') assert False, 'Something failed' """) result = testdir.runpytest("--tb=short") - result.stdout.fnmatch_lines(["!This is stdout!"]) - result.stdout.fnmatch_lines(["!This is stderr!"]) - - result = testdir.runpytest("--show-capture=both", "--tb=short") - result.stdout.fnmatch_lines(["!This is stdout!"]) - result.stdout.fnmatch_lines(["!This is stderr!"]) - - result = testdir.runpytest("--show-capture=stdout", "--tb=short") - assert "!This is stderr!" not in result.stdout.str() - assert "!This is stdout!" in result.stdout.str() - - result = testdir.runpytest("--show-capture=stderr", "--tb=short") - assert "!This is stdout!" not in result.stdout.str() - assert "!This is stderr!" in result.stdout.str() - - result = testdir.runpytest("--show-capture=no", "--tb=short") - assert "!This is stdout!" not in result.stdout.str() - assert "!This is stderr!" not in result.stdout.str() + result.stdout.fnmatch_lines(["!This is stdout!", + "!This is stderr!", + "*WARNING*!This is a warning log msg!"]) + + result = testdir.runpytest("--show-capture=all", "--tb=short") + result.stdout.fnmatch_lines(["!This is stdout!", + "!This is stderr!", + "*WARNING*!This is a warning log msg!"]) + + stdout = testdir.runpytest( + "--show-capture=stdout", "--tb=short").stdout.str() + assert "!This is stderr!" not in stdout + assert "!This is stdout!" in stdout + assert "!This is a warning log msg!" not in stdout + + stdout = testdir.runpytest( + "--show-capture=stderr", "--tb=short").stdout.str() + assert "!This is stdout!" not in stdout + assert "!This is stderr!" in stdout + assert "!This is a warning log msg!" not in stdout + + stdout = testdir.runpytest( + "--show-capture=log", "--tb=short").stdout.str() + assert "!This is stdout!" not in stdout + assert "!This is stderr!" not in stdout + assert "!This is a warning log msg!" in stdout + + stdout = testdir.runpytest( + "--show-capture=no", "--tb=short").stdout.str() + assert "!This is stdout!" not in stdout + assert "!This is stderr!" not in stdout + assert "!This is a warning log msg!" not in stdout @pytest.mark.xfail("not hasattr(os, 'dup')")