Files
awesome-python/website/data/category_intros/cli-development.md
T

5.8 KiB

Python's own argparse covers basic command-line apps. Beyond that, pick Click or Typer as your Python CLI library, and style the output with Rich.

How to choose:

  • Basic command-line app with no dependencies: argparse
  • Nested commands, or subcommands loaded lazily: Click
  • Options declared once as type-hinted function parameters: Typer
  • Help text read from your docstrings: cyclopts
  • Progress bar for a loop: tqdm, or alive-progress for animated bars
  • Colored text, tables, and logs: Rich, or colorama for ANSI colors on Windows
  • ASCII-art banners: pyfiglet
  • Full-screen app in the terminal or a browser: Textual
  • Interactive prompts and REPLs: prompt_toolkit
  • Terminal widgets on an event loop you already run: Urwid
  • Full-screen forms and ASCII animations: asciimatics

argparse is in the standard library. Python's docs call it the recommended choice when you have no more specific needs, since it gives you the most out of the box for the least code. It writes the help and usage messages and reports invalid arguments for you. For commands written as decorated functions, the same docs point to Click, and for a CLI that works with static type checking, to Typer.

Click builds a CLI from commands declared with decorators. You can nest them to any depth, and Click can load subcommands lazily at runtime. It also reads option values from environment variables and comes with helpers for ANSI colors, terminal size, and launching editors.

Typer builds a CLI from your function signatures: you declare each argument and option once, as a type-hinted function parameter. Write those hints with Annotated, which its tutorial recommends wherever possible. Its docs say you get the best results by pairing it with Rich: Typer structures the commands and options, and Rich displays the output.

cyclopts also builds a CLI from type-hinted functions, but reads the help text from your docstrings. Its docs call that the preferred way to document a command, and reach for Annotated with Parameter only when you need more control. It follows Python's own argument binding rules, so a parameter can be passed by position or as a keyword. It has its own parser, with no Click underneath. Register commands with @app.command, and the function to run when no command matches with @app.default.

tqdm adds a progress bar to any loop: wrap the iterable in tqdm(). Import it from tqdm.auto, which picks the console bar or the Jupyter widget for you. alive-progress wraps the loop in an alive_bar context manager instead, with a spinner that speeds up and slows down with your throughput.

Rich writes colored text, tables, Markdown, and syntax-highlighted code to the terminal. Start with its drop-in print, then create one Console at module level for the rest of your app. For colored logs, send the logging module's output through RichHandler.

colorama makes ANSI escape codes work on Windows and does nothing on other platforms. If that's all you need, call just_fix_windows_console().

pyfiglet is a full port of FIGlet into pure Python: it renders text in ASCII-art fonts, as in pyfiglet.figlet_format("text", font="slant").

Textual apps run in the terminal, and the textual serve command from textual-dev serves them in a browser. Build one by subclassing App, and style its widgets with CSS.

prompt_toolkit is for interactive input. It can replace GNU readline or build full-screen apps. For a REPL, use a PromptSession, which keeps the history for the whole session.

Urwid is a console widget construction set rather than a finished UI library. It runs on your choice of event loop: asyncio, or another one you already use. It's licensed under the LGPL, while Textual and asciimatics use permissive licenses.

asciimatics does full-screen text UIs, from interactive forms to ASCII animations: create a Screen, build a Scene from Effect objects, and let the Screen play it.

Ship your CLI as an installable package with a [project.scripts] entry point, not a file users run with python. Click recommends it, and shell completion in Click and Typer works through that entry point. Test your commands in-process: Click and Typer both provide a CliRunner, and Textual's run_test() drives your app as if you were using the keyboard and mouse.