|
from __future__ import annotations |
|
|
|
import io |
|
import sys |
|
from typing import ContextManager, TextIO |
|
|
|
from .base import DummyInput, Input, PipeInput |
|
|
|
__all__ = [ |
|
"create_input", |
|
"create_pipe_input", |
|
] |
|
|
|
|
|
def create_input(stdin: TextIO | None = None, always_prefer_tty: bool = False) -> Input: |
|
""" |
|
Create the appropriate `Input` object for the current os/environment. |
|
|
|
:param always_prefer_tty: When set, if `sys.stdin` is connected to a Unix |
|
`pipe`, check whether `sys.stdout` or `sys.stderr` are connected to a |
|
pseudo terminal. If so, open the tty for reading instead of reading for |
|
`sys.stdin`. (We can open `stdout` or `stderr` for reading, this is how |
|
a `$PAGER` works.) |
|
""" |
|
if sys.platform == "win32": |
|
from .win32 import Win32Input |
|
|
|
|
|
|
|
if stdin is None and sys.stdin is None: |
|
return DummyInput() |
|
|
|
return Win32Input(stdin or sys.stdin) |
|
else: |
|
from .vt100 import Vt100Input |
|
|
|
|
|
if stdin is None: |
|
stdin = sys.stdin |
|
|
|
if always_prefer_tty: |
|
for obj in [sys.stdin, sys.stdout, sys.stderr]: |
|
if obj.isatty(): |
|
stdin = obj |
|
break |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
stdin.fileno() |
|
except io.UnsupportedOperation: |
|
return DummyInput() |
|
|
|
return Vt100Input(stdin) |
|
|
|
|
|
def create_pipe_input() -> ContextManager[PipeInput]: |
|
""" |
|
Create an input pipe. |
|
This is mostly useful for unit testing. |
|
|
|
Usage:: |
|
|
|
with create_pipe_input() as input: |
|
input.send_text('inputdata') |
|
|
|
Breaking change: In prompt_toolkit 3.0.28 and earlier, this was returning |
|
the `PipeInput` directly, rather than through a context manager. |
|
""" |
|
if sys.platform == "win32": |
|
from .win32_pipe import Win32PipeInput |
|
|
|
return Win32PipeInput.create() |
|
else: |
|
from .posix_pipe import PosixPipeInput |
|
|
|
return PosixPipeInput.create() |
|
|