MCPcopy
hub / github.com/pallets/click / test_capture_fd_logging_handler

Function test_capture_fd_logging_handler

tests/test_testing.py:600–642  ·  view source on GitHub ↗

capture='fd' captures logging output from a handler holding a stale stderr reference (issue #2827). stdlib logging.StreamHandler grabs sys.stderr at configuration time. Under normal CliRunner (sys-level capture), the handler still writes to the original stream object and output is l

(tmp_path)

Source from the content-addressed store, hash-verified

598
599@needs_fd_capture
600def test_capture_fd_logging_handler(tmp_path):
601 """capture='fd' captures logging output from a handler holding a stale
602 stderr reference (issue #2827).
603
604 stdlib logging.StreamHandler grabs sys.stderr at configuration time.
605 Under normal CliRunner (sys-level capture), the handler still writes
606 to the original stream object and output is lost. fd-level capture
607 redirects the underlying file descriptor, so the writes are captured.
608 """
609 import logging
610
611 # Create a writer backed by the real fd 2, simulating a handler
612 # configured at import time before pytest or CliRunner replaced
613 # sys.stderr. open(2, closefd=False) mirrors the real scenario:
614 # the original sys.stderr is a TextIOWrapper -> BufferedWriter ->
615 # FileIO(fd=2).
616 stale_stderr = open(2, "w", closefd=False) # noqa: SIM115
617 handler = logging.StreamHandler(stale_stderr)
618 handler.setFormatter(logging.Formatter("%(message)s"))
619
620 logger = logging.getLogger(f"click_test_{tmp_path.name}")
621 logger.addHandler(handler)
622 logger.setLevel(logging.INFO)
623 logger.propagate = False
624
625 @click.command()
626 def cli():
627 logger.info("log from stale handler")
628 click.echo("normal echo")
629
630 # sys-level capture misses the log line (it bypasses sys.stderr).
631 runner_sys = CliRunner(capture="sys")
632 result_sys = runner_sys.invoke(cli)
633 assert "normal echo" in result_sys.output
634 assert "log from stale handler" not in result_sys.output
635
636 # fd-level capture catches it by redirecting fd 2.
637 runner_fd = CliRunner(capture="fd")
638 result_fd = runner_fd.invoke(cli)
639 assert "normal echo" in result_fd.output
640 assert "log from stale handler" in result_fd.output
641
642 logger.removeHandler(handler)
643
644
645@needs_fd_capture

Callers

nothing calls this directly

Calls 3

invokeMethod · 0.95
CliRunnerClass · 0.90
openFunction · 0.85

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…