1from __future__ import annotations 
    2 
    3import io 
    4import sys 
    5from typing import ContextManager, TextIO 
    6 
    7from .base import DummyInput, Input, PipeInput 
    8 
    9__all__ = [ 
    10    "create_input", 
    11    "create_pipe_input", 
    12] 
    13 
    14 
    15def create_input(stdin: TextIO | None = None, always_prefer_tty: bool = False) -> Input: 
    16    """ 
    17    Create the appropriate `Input` object for the current os/environment. 
    18 
    19    :param always_prefer_tty: When set, if `sys.stdin` is connected to a Unix 
    20        `pipe`, check whether `sys.stdout` or `sys.stderr` are connected to a 
    21        pseudo terminal. If so, open the tty for reading instead of reading for 
    22        `sys.stdin`. (We can open `stdout` or `stderr` for reading, this is how 
    23        a `$PAGER` works.) 
    24    """ 
    25    if sys.platform == "win32": 
    26        from .win32 import Win32Input 
    27 
    28        # If `stdin` was assigned `None` (which happens with pythonw.exe), use 
    29        # a `DummyInput`. This triggers `EOFError` in the application code. 
    30        if stdin is None and sys.stdin is None: 
    31            return DummyInput() 
    32 
    33        return Win32Input(stdin or sys.stdin) 
    34    else: 
    35        from .vt100 import Vt100Input 
    36 
    37        # If no input TextIO is given, use stdin/stdout. 
    38        if stdin is None: 
    39            stdin = sys.stdin 
    40 
    41            if always_prefer_tty: 
    42                for obj in [sys.stdin, sys.stdout, sys.stderr]: 
    43                    if obj.isatty(): 
    44                        stdin = obj 
    45                        break 
    46 
    47        # If we can't access the file descriptor for the selected stdin, return 
    48        # a `DummyInput` instead. This can happen for instance in unit tests, 
    49        # when `sys.stdin` is patched by something that's not an actual file. 
    50        # (Instantiating `Vt100Input` would fail in this case.) 
    51        try: 
    52            stdin.fileno() 
    53        except io.UnsupportedOperation: 
    54            return DummyInput() 
    55 
    56        return Vt100Input(stdin) 
    57 
    58 
    59def create_pipe_input() -> ContextManager[PipeInput]: 
    60    """ 
    61    Create an input pipe. 
    62    This is mostly useful for unit testing. 
    63 
    64    Usage:: 
    65 
    66        with create_pipe_input() as input: 
    67            input.send_text('inputdata') 
    68 
    69    Breaking change: In prompt_toolkit 3.0.28 and earlier, this was returning 
    70    the `PipeInput` directly, rather than through a context manager. 
    71    """ 
    72    if sys.platform == "win32": 
    73        from .win32_pipe import Win32PipeInput 
    74 
    75        return Win32PipeInput.create() 
    76    else: 
    77        from .posix_pipe import PosixPipeInput 
    78 
    79        return PosixPipeInput.create()