When CliRunner(mix_stderr=False) is used, the output of print("foo", file=sys.stderr) is not captured. click.echo("foo", err=True) is captured (and this is tested in the test_stderr() test) but the output from print() is not captured.
Modifying tests/testing.py::test_stderr as follows demonstrates the bug:
def test_stderr():
@click.command()
def cli_stderr():
click.echo("stdout")
click.echo("stderr", err=True)
print("sys.stderr", file=sys.stderr)
runner = CliRunner(mix_stderr=False)
result = runner.invoke(cli_stderr)
assert result.output == "stdout\n"
assert result.stdout == "stdout\n"
assert result.stderr == "stderr\nsys.stderr\n"
runner_mix = CliRunner(mix_stderr=True)
result_mix = runner_mix.invoke(cli_stderr)
assert result_mix.output == "stdout\nstderr\nsys.stderr\n"
assert result_mix.stdout == "stdout\nstderr\nsys.stderr\n"
with pytest.raises(ValueError):
result_mix.stderr
@click.command()
def cli_empty_stderr():
click.echo("stdout")
runner = CliRunner(mix_stderr=False)
result = runner.invoke(cli_empty_stderr)
assert result.output == "stdout\n"
assert result.stdout == "stdout\n"
assert result.stderr == ""
Running this test, produces:
__________________________________________________________________________________ test_stderr ___________________________________________________________________________________
def test_stderr():
@click.command()
def cli_stderr():
click.echo("stdout")
click.echo("stderr", err=True)
print("sys.stderr", file=sys.stderr)
runner = CliRunner(mix_stderr=False)
result = runner.invoke(cli_stderr)
assert result.output == "stdout\n"
assert result.stdout == "stdout\n"
> assert result.stderr == "stderr\nsys.stderr\n"
E AssertionError: assert 'stderr\n' == 'stderr\nsys.stderr\n'
E stderr
E - sys.stderr
tests/test_testing.py:316: AssertionError
============================================================================ short test summary info =============================================================================
FAILED tests/test_testing.py::test_stderr - AssertionError: assert 'stderr\n' == 'stderr\nsys.stderr\n'
=============================================================================== 1 failed in 0.09s ================================================================================
The fix appears to be flusing stderr in src/click/testing.py:
--- a/src/click/testing.py
+++ b/src/click/testing.py
@@ -437,6 +437,7 @@ class CliRunner:
if self.mix_stderr:
stderr = None
else:
+ sys.stderr.flush()
stderr = outstreams[1].getvalue() # type: ignore
With this fix, and the modified test_stderr(), all tests pass.
Environment:
- OS: macOS Ventura 13.5.1, Intel x86
- Python version: Python 3.11.6 (v3.11.6:8b6ee5ba3b, Oct 2 2023, 11:18:21) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
- Click version:
version = "8.2.0.dev"
If you confirm this is a bug and not the intended behavior I am happy to submit a PR.
When
CliRunner(mix_stderr=False)is used, the output ofprint("foo", file=sys.stderr)is not captured.click.echo("foo", err=True)is captured (and this is tested in thetest_stderr()test) but the output fromprint()is not captured.Modifying
tests/testing.py::test_stderras follows demonstrates the bug:Running this test, produces:
The fix appears to be flusing stderr in
src/click/testing.py:With this fix, and the modified
test_stderr(), all tests pass.Environment:
version = "8.2.0.dev"If you confirm this is a bug and not the intended behavior I am happy to submit a PR.