Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add captured-log support to --show-capture #3234

Merged
merged 4 commits into from Feb 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 10 additions & 9 deletions _pytest/debugging.py
Expand Up @@ -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)
Expand Down
14 changes: 7 additions & 7 deletions _pytest/terminal.py
Expand Up @@ -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',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good thinking, just realized that we definitely should have used all instead of both from the beginning. 😉

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).")
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion 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).
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).
1 change: 1 addition & 0 deletions changelog/3204.feature
@@ -0,0 +1 @@
Captured logs are printed before entering pdb.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reminds me, please update 1478.feature as well. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does towncrier reference this PR (#3234) then, or do we have to update the generated changelog manually?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It uses the number in the filename to create a link, so the file above will link to #3204

22 changes: 3 additions & 19 deletions doc/en/logging.rst
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions testing/test_pdb.py
Expand Up @@ -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
Expand Down
52 changes: 34 additions & 18 deletions testing/test_terminal.py
Expand Up @@ -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')")
Expand Down