Page through text by invoking a program on a temporary file. Used as the primary pager strategy on Windows (where piping to ``more`` adds spurious ``\\r\\n``), and as a fallback on other platforms. The command is resolved to an absolute path with :func:`shutil.which`.
(
cmd_parts: list[str], color: bool | None = None
)
| 578 | |
| 579 | @contextlib.contextmanager |
| 580 | def _tempfilepager( |
| 581 | cmd_parts: list[str], color: bool | None = None |
| 582 | ) -> t.Iterator[tuple[t.BinaryIO | t.TextIO, str, bool]]: |
| 583 | """Page through text by invoking a program on a temporary file. |
| 584 | |
| 585 | Used as the primary pager strategy on Windows (where piping to |
| 586 | ``more`` adds spurious ``\\r\\n``), and as a fallback on other |
| 587 | platforms. The command is resolved to an absolute path with |
| 588 | :func:`shutil.which`. |
| 589 | """ |
| 590 | # Split the command into the invoked CLI and its parameters. |
| 591 | if not cmd_parts: |
| 592 | # No usable pager: fall back to stdout through _nullpager so it gets the |
| 593 | # same borrowed-stream handling and the caller's stream is not closed. |
| 594 | stdout = _default_text_stdout() or StringIO() |
| 595 | with _nullpager(stdout, color) as rv: |
| 596 | yield rv |
| 597 | return |
| 598 | |
| 599 | import shutil |
| 600 | import subprocess |
| 601 | |
| 602 | cmd = cmd_parts[0] |
| 603 | |
| 604 | cmd_filepath = shutil.which(cmd) |
| 605 | if not cmd_filepath: |
| 606 | # No usable pager: fall back to stdout through _nullpager so it gets the |
| 607 | # same borrowed-stream handling and the caller's stream is not closed. |
| 608 | stdout = _default_text_stdout() or StringIO() |
| 609 | with _nullpager(stdout, color) as rv: |
| 610 | yield rv |
| 611 | return |
| 612 | |
| 613 | # Produces a normalized absolute path string. |
| 614 | # multi-call binaries such as busybox derive their identity from the symlink |
| 615 | # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) |
| 616 | cmd_path = Path(cmd_filepath).absolute() |
| 617 | |
| 618 | import tempfile |
| 619 | |
| 620 | encoding = get_best_encoding(sys.stdout) |
| 621 | if color is None: |
| 622 | color = False |
| 623 | # On Windows, NamedTemporaryFile cannot be opened by another process |
| 624 | # while Python still has it open, so we use delete=False and clean up manually |
| 625 | # rather than using a contextmanager here. |
| 626 | f = tempfile.NamedTemporaryFile(mode="wb", delete=False) |
| 627 | try: |
| 628 | yield t.cast(t.BinaryIO, f), encoding, color |
| 629 | f.flush() |
| 630 | f.close() |
| 631 | subprocess.call([str(cmd_path), f.name]) |
| 632 | finally: |
| 633 | os.unlink(f.name) |
| 634 | |
| 635 | |
| 636 | @contextlib.contextmanager |
no test coverage detected