cadrumo.core.tty module¶
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, the
master-key passphrase prompt), and by recovery enrollment. The probe itself is
layer-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 for
the adapters that needed it most: entrypoints is the TOP layer of the
hexagonal contract, so nothing beneath it may import from there. Each caller
therefore open-coded sys.stdin.isatty() instead, and the CLI module’s
docstring went on claiming to centralise “the rules every CLI command uses”
while nothing imported it at all. The primitive moved down; the CLI keeps the
policy built on top of it (colour, progress widgets, typed refusals).
Bare ``stream.isatty()`` is not equivalent to these helpers. It raises
rather than answering when the stream is missing, closed, or detached — the
precise conditions a headless or service host presents, which is when the
question is being asked. These helpers answer False instead, so a caller
guarding an interactive flow refuses cleanly rather than dying inside its own
guard.
A truthy answer here is necessary but NOT always sufficient. On Windows both
the 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 read
from a console pairs this with a real-console probe (see
entrypoints/cli/config/secure_input.py) rather than replacing that
stricter check with this one.
- stream_is_tty(stream)[source]¶
Return whether
streamis attached to an interactive terminal.Answers
False— never raises — for a stream that isNone, exposes no callableisatty, has been closed (ValueError), or whoseisatty()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.