Stdout vs stderr
Overview
When code prints things, it actually writes to one of two virtual files: "standard output" or "standard error".
- For a human user, there's usually no difference: Both
stdout
andstderr
are visible on the terminal. - For machines, there's a difference: A script consuming the output of your script "sees" only
stdout
.
Distinguishing between stdout
and stderr
, is one of the Basics recommended by the CLIG
TLDR
- Send output that can be piped and consumed by a next script to
stdout
. - Send everything else, especially errors and log messages to
stderr
.
For more explanation, on stdout
and stderr
, see also the Typer Docs
Printing to stdout
vs stderr
with Rich
In Rich, you use a rich.console.Console
object for printing.
- By default, it prints to
stdout
. - You can initialize the
Console
withstderr=True
, so that it prints tostderr
.
After creating a talk, print:
- the talk ID to
stdout
- a logging message to
stderr
from rich.console import Console
stdout_console = Console()
stderr_console = Console(stderr=True)
stdout_console.print(talk.talk_id)
stderr_console.print("New talk created. 🪅")
Testing
For tests with typer.testing.CliRunner
, it's recommended to verify the content of stdout
and stdin
separately.
In order to do that, you need to initialize the typer.testing.CliRunner
instance with mix_stderr=False
.
Iteration vs Keeping the Interface Stable
Changing output for humans is usually OK. The only way to make an interface easy to use is to iterate on it, and if the output is considered an interface, then you can’t iterate on it. Encourage your users to use --plain or --json in scripts to keep output stable (see Output).
CLIG Guidelines / Future-proofing