The Question :
469 people think this question is useful
Sometimes I want to just insert some print statements in my code, and see what gets printed out when I exercise it. My usual way to “exercise” it is with existing pytest tests. But when I run these, I don’t seem able to see any standard output (at least from within PyCharm, my IDE).
Is there a simple way to see standard output during a pytest run?
The Question Comments :
The Answer 1
637 people think this answer is useful
-s switch disables per-test capturing (only if a test fails).
The Answer 2
59 people think this answer is useful
pytest captures the stdout from individual tests and displays them only on certain conditions, along with the summary of the tests it prints by default.
Extra summary info can be shown using the ‘-r’ option:
shows the captured output of passed tests.
shows the captured output of failed tests (default behaviour).
The formatting of the output is prettier with -r than with -s.
The Answer 3
54 people think this answer is useful
In an upvoted comment to the accepted answer, Joe asks:
Is there any way to print to the console AND capture the output so that it shows in the junit report?
In UNIX, this is commonly referred to as teeing. Ideally, teeing rather than capturing would be the py.test default. Non-ideally, neither py.test nor any existing third-party py.test plugin (…that I know of, anyway) supports teeing – despite Python trivially supporting teeing out-of-the-box.
Monkey-patching py.test to do anything unsupported is non-trivial. Why? Because:
- Most py.test functionality is locked behind a private
_pytest package not intended to be externally imported. Attempting to do so without knowing what you’re doing typically results in the public
pytest package raising obscure exceptions at runtime. Thanks alot, py.test. Really robust architecture you got there.
- Even when you do figure out how to monkey-patch the private
_pytest API in a safe manner, you have to do so before running the public
pytest package run by the external
py.test command. You cannot do this in a plugin (e.g., a top-level
conftest module in your test suite). By the time py.test lazily gets around to dynamically importing your plugin, any py.test class you wanted to monkey-patch has long since been instantiated – and you do not have access to that instance. This implies that, if you want your monkey-patch to be meaningfully applied, you can no longer safely run the external
py.test command. Instead, you have to wrap the running of that command with a custom setuptools
test command that (in order):
- Monkey-patches the private
- Calls the public
pytest.main() function to run the
This answer monkey-patches py.test’s
--capture=no options to capture stderr but not stdout. By default, these options capture neither stderr nor stdout. This isn’t quite teeing, of course. But every great journey begins with a tedious prequel everyone forgets in five years.
Why do this? I shall now tell you. My py.test-driven test suite contains slow functional tests. Displaying the stdout of these tests is helpful and reassuring, preventing leycec from reaching for
killall -9 py.test when yet another long-running functional test fails to do anything for weeks on end. Displaying the stderr of these tests, however, prevents py.test from reporting exception tracebacks on test failures. Which is completely unhelpful. Hence, we coerce py.test to capture stderr but not stdout.
Before we get to it, this answer assumes you already have a custom setuptools
test command invoking py.test. If you don’t, see the Manual Integration subsection of py.test’s well-written Good Practices page.
Do not install pytest-runner, a third-party setuptools plugin providing a custom setuptools
test command also invoking py.test. If pytest-runner is already installed, you’ll probably need to uninstall that pip3 package and then adopt the manual approach linked to above.
Assuming you followed the instructions in Manual Integration highlighted above, your codebase should now contain a
PyTest.run_tests() method. Modify this method to resemble:
# Import the public "pytest" package *BEFORE* the private "_pytest"
# package. While importation order is typically ignorable, imports can
# technically have side effects. Tragicomically, that is the case here.
# Importing the public "pytest" package establishes runtime
# configuration required by submodules of the private "_pytest" package.
# The former *MUST* always be imported before the latter. Failing to do
# so raises obtuse exceptions at runtime... which is bad.
from _pytest.capture import CaptureManager, FDCapture, MultiCapture
# If the private method to be monkey-patched no longer exists, py.test
# is either broken or unsupported. In either case, raise an exception.
if not hasattr(CaptureManager, '_getcapture'):
from distutils.errors import DistutilsClassError
'Class "pytest.capture.CaptureManager" method _getcapture() '
'not found. The current version of py.test is either '
'broken (unlikely) or unsupported (likely).'
# Old method to be monkey-patched.
_getcapture_old = CaptureManager._getcapture
# New method applying this monkey-patch. Note the use of:
# * "out=False", *NOT* capturing stdout.
# * "err=True", capturing stderr.
def _getcapture_new(self, method):
if method == "no":
out=False, err=True, in_=False, Capture=FDCapture)
return _getcapture_old(self, method)
# Replace the old with the new method.
CaptureManager._getcapture = _getcapture_new
# Run py.test with all passed arguments.
errno = pytest.main(self.pytest_args)
To enable this monkey-patch, run py.test as follows:
python setup.py test -a "-s"
Stderr but not stdout will now be captured. Nifty!
Extending the above monkey-patch to tee stdout and stderr is left as an exercise to the reader with a barrel-full of free time.
The Answer 4
37 people think this answer is useful
When running the test use the
-s option. All print statements in
exampletest.py would get printed on the console when test is run.
py.test exampletest.py -s
The Answer 5
33 people think this answer is useful
According to pytest documentation, version 3 of pytest can temporary disable capture in a test:
print('this output is captured')
print('output not captured, going directly to sys.stdout')
print('this output is also captured')
The Answer 6
19 people think this answer is useful
pytest -s -v test_login.py for more info in console.
-v it’s a short
-s means ‘disable all capturing’
The Answer 7
12 people think this answer is useful
pytest --capture=tee-sys was recently added (v5.4.0). You can capture as well as see the output on stdout/err.
The Answer 8
4 people think this answer is useful
If you are using PyCharm IDE, then you can run that individual test or all tests using Run toolbar. The Run tool window displays output generated by your application and you can see all the print statements in there as part of test output.
The Answer 9
2 people think this answer is useful
You can also enable live-logging by setting the following in
tox.ini in your project root.
log_cli = True
Or specify it directly on cli
pytest -o log_cli=True
The Answer 10
2 people think this answer is useful
pytest test_name.py -v -s
The Answer 11
-3 people think this answer is useful
The other answers don’t work. The only way to see the captured output is using the following flag:
pytest –show-capture all