"""The one terminal-attachment probe, usable from every layer.Whether a stream is attached to an interactive terminal is asked by the CLI,by adapters that must refuse a non-interactive flow (Google OAuth consent, themaster-key passphrase prompt), and by recovery enrollment. The probe itself islayer-free, so it lives in ``core`` where all of them may import it.It lived in ``entrypoints/cli/_tty.py`` first, which made it unreachable forthe adapters that needed it most: ``entrypoints`` is the TOP layer of thehexagonal contract, so nothing beneath it may import from there. Each callertherefore open-coded ``sys.stdin.isatty()`` instead, and the CLI module'sdocstring went on claiming to centralise "the rules every CLI command uses"while nothing imported it at all. The primitive moved down; the CLI keeps thepolicy built on top of it (colour, progress widgets, typed refusals).**Bare ``stream.isatty()`` is not equivalent to these helpers.** It raisesrather than answering when the stream is missing, closed, or detached — theprecise conditions a headless or service host presents, which is when thequestion is being asked. These helpers answer ``False`` instead, so a callerguarding an interactive flow refuses cleanly rather than dying inside its ownguard.A truthy answer here is necessary but NOT always sufficient. On Windows boththe ``NUL`` device and a console-less host can report ``isatty() is True``while no console exists to type into, so a caller that must genuinely readfrom a console pairs this with a real-console probe (see``entrypoints/cli/config/secure_input.py``) rather than replacing thatstricter check with this one."""from__future__importannotationsimportsysfromtypingimportIO,Any__all__=["stderr_is_tty","stdin_is_tty","stdout_is_tty","stream_is_tty",]# ANY-RETURN-RATIONALE-STREAM-DUCK-TYPE: accepts any stream-like object by# design (real streams, closed streams, non-stream objects) and probes it# structurally via getattr/hasattr rather than a concrete stream protocol.
[docs]defstream_is_tty(stream:IO[Any]|object|None)->bool:"""Return whether ``stream`` is attached to an interactive terminal. Answers ``False`` — never raises — for a stream that is ``None``, exposes no callable ``isatty``, has been closed (``ValueError``), or whose ``isatty()`` fails at the OS level (``OSError``). Every one of those means "no terminal here" for the caller's purpose, and a probe guarding an interactive flow must not itself be the thing that raises. Args: stream: A stream-like object, or ``None``. Returns: ``True`` only when the stream reports an interactive terminal. """isatty=getattr(stream,"isatty",None)ifnotcallable(isatty):returnFalsetry:returnbool(isatty())except(OSError,ValueError):returnFalse
[docs]defstdin_is_tty()->bool:"""Return whether stdin is attached to an interactive terminal."""returnstream_is_tty(sys.stdin)
[docs]defstdout_is_tty()->bool:"""Return whether stdout is attached to an interactive terminal."""returnstream_is_tty(sys.stdout)
[docs]defstderr_is_tty()->bool:"""Return whether stderr is attached to an interactive terminal."""returnstream_is_tty(sys.stderr)