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 | class="st">"""capture=&class="cm">#x27;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&class="cm">#x27;s underlying |
| 579 | FileIO uses fd 1, so redirecting fd 1 captures its writes. |
| 580 | class="st">""" |
| 581 | class="cm"># open(1, ..., closefd=False) creates a writer whose underlying |
| 582 | class="cm"># FileIO uses fd 1 directly. This mirrors the real scenario: |
| 583 | class="cm"># the original sys.stdout is a TextIOWrapper -> BufferedWriter -> |
| 584 | class="cm"># FileIO(fd=1). |
| 585 | stale_stdout = open(1, class="st">"w", closefd=False) class="cm"># noqa: SIM115 |
| 586 | |
| 587 | @click.command() |
| 588 | def cli(): |
| 589 | stale_stdout.write(class="st">"stale write\n") |
| 590 | stale_stdout.flush() |
| 591 | click.echo(class="st">"normal write") |
| 592 | |
| 593 | runner = CliRunner(capture=class="st">"fd") |
| 594 | result = runner.invoke(cli) |
| 595 | assert class="st">"normal write" in result.stdout |
| 596 | assert class="st">"stale write" in result.stdout |
| 597 | |
| 598 | |
| 599 | @needs_fd_capture |