capture='fd' captures writes from stale stdout references (issue #2874). Simulates ``from sys import stdout`` at import time, which grabs the real stdout connected to fd 1. The stale object's underlying FileIO uses fd 1, so redirecting fd 1 captures its writes.
()
| 572 | |
| 573 | @needs_fd_capture |
| 574 | def test_capture_fd_stale_reference(): |
| 575 | """capture='fd' captures writes from stale stdout references (issue #2874). |
| 576 | |
| 577 | Simulates ``from sys import stdout`` at import time, which grabs |
| 578 | the real stdout connected to fd 1. The stale object's underlying |
| 579 | FileIO uses fd 1, so redirecting fd 1 captures its writes. |
| 580 | """ |
| 581 | # open(1, ..., closefd=False) creates a writer whose underlying |
| 582 | # FileIO uses fd 1 directly. This mirrors the real scenario: |
| 583 | # the original sys.stdout is a TextIOWrapper -> BufferedWriter -> |
| 584 | # FileIO(fd=1). |
| 585 | stale_stdout = open(1, "w", closefd=False) # noqa: SIM115 |
| 586 | |
| 587 | @click.command() |
| 588 | def cli(): |
| 589 | stale_stdout.write("stale write\n") |
| 590 | stale_stdout.flush() |
| 591 | click.echo("normal write") |
| 592 | |
| 593 | runner = CliRunner(capture="fd") |
| 594 | result = runner.invoke(cli) |
| 595 | assert "normal write" in result.stdout |
| 596 | assert "stale write" in result.stdout |
| 597 | |
| 598 | |
| 599 | @needs_fd_capture |