Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Version 8.2.1
- Fix flag value handling for flag options with a provided type. :issue:`2894`
:issue:`2897` :pr:`2930`
- Fix shell completion for nested groups. :issue:`2906` :pr:`2907`
- Flush ``sys.stderr`` at the end of ``CliRunner.invoke``. :issue:`2682`

Version 8.2.0
-------------
Expand Down
1 change: 1 addition & 0 deletions src/click/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ def invoke(
exc_info = sys.exc_info()
finally:
sys.stdout.flush()
sys.stderr.flush()
stdout = outstreams[0].getvalue()
stderr = outstreams[1].getvalue()
output = outstreams[2].getvalue()
Expand Down
21 changes: 21 additions & 0 deletions tests/test_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,24 @@ def test_isolation_stderr_errors():
click.echo("\udce2", err=True, nl=False)

assert err.getvalue() == b"\\udce2"


def test_isolation_flushes_unflushed_stderr():
"""An un-flushed write to stderr, as with `print(..., file=sys.stderr)`, will end up
flushed by the runner at end of invocation.
"""
runner = CliRunner()

with runner.isolation() as (_, err, _):
click.echo("\udce2", err=True, nl=False)

assert err.getvalue() == b"\\udce2"

@click.command()
def cli():
# set end="", flush=False so that it's totally clear that we won't get any
# auto-flush behaviors
print("gyarados gyarados gyarados", file=sys.stderr, end="", flush=False)

result = runner.invoke(cli)
assert result.stderr == "gyarados gyarados gyarados"