pyssg is pre-1.0 and under active development - APIs, config, and themes may change.
pyssg.cli.app

1 min read

pyssg.cli.app

The root Typer application and the main(argv) -> int entry point.

The CLI is a Typer (Click) command tree rooted at :data:app. A single global option -- --site -- lives on the root callback so it can appear before the subcommand (pyssg --site PATH build); commands read it back via :func:site_from.

:func:main adapts Typer to the process-exit contract the rest of the project relies on: it returns an int exit code for application outcomes (so callers and tests can do rc = main([...])), while usage/parse errors propagate as SystemExit exactly as argparse did. It runs the command in Click's non-standalone mode and maps the result:

  • a command that finishes (returning None or raising typer.Exit(code)) yields that exit code as an int;
  • a usage error (unknown command, bad option, missing required subcommand) is shown and re-raised as SystemExit with Click's exit code;
  • an aborted prompt becomes SystemExit(1).

class AppContext

Process-global CLI state, stored on the Click context's obj.

Currently just the --site directory; kept as a small object so new global options can be threaded to commands without changing every signature.

site_from(ctx: typer.Context) -> Path

Return the --site path captured by the root callback.

Commands call this instead of declaring --site themselves, so the option stays global (parsed before the subcommand) and there is a single source of truth for the site directory.

main(argv: list[str] | None = None) -> int

Run the CLI and return a process exit code.

See the module docstring for the result/exception mapping. argv defaults to sys.argv[1:] when None, matching argparse.

The Click command is resolved on each call (after all command modules have registered via the package __init__); get_command only reads the already-built Typer registry, so this is cheap.