CLI System
pyrig provides a fully inheritable, automatically extensible CLI that every project built on pyrig gets for free. The system is built on Typer but adds a dynamic command-discovery layer on top, so projects never need to touch pyrig's source code to gain or override CLI commands.
How the CLI is Inherited
When a project declares pyrig as a dependency it gets a working CLI entry point
automatically. The only thing required is registering a console-script in
pyproject.toml that points to the same main function pyrig uses.
This is also handled automatically by pyrig via its PyprojectConfigFile
and pyrig mkroot:
[project.scripts]
my-project = "pyrig.rig.cli.main:main"
From that point on, uv run my-project <command> delegates to pyrig's entry
point, which discovers and registers the right commands for the calling project
automatically at runtime.
The Typer App
A RigDependencySubclass named CLI is defined in pyrig.rig.cli.cli.cli.
Its app() method builds a fully configured typer.Typer application that
registers every function defined in my_project.rig.cli.subcommands as a command.
Functions from shared_subcommands modules across all packages in the
dependency chain are also registered. Because CLI is a RigDependencySubclass,
a dependent project can override any step of the build by subclassing it.
Command Discovery
When the CLI is invoked, pyrig discovers every function defined in
my_project.rig.cli.subcommands and registers them as CLI commands.
Additionally, it discovers functions from shared_subcommands modules across
all packages in the dependency chain (pyrig and all packages that depend on it).
This means that to add a new command, simply define a new function in one of
those modules, and it will be automatically available as a CLI command the next
time the CLI is run. Simply run pyrig mkcmd <command-name> to append a new
command function skeleton to my_project.rig.cli.subcommands (creating the file
if it does not exist).
my_project.rig.cli.shared_subcommands is a bit special: it is intended for
commands that should be shared across multiple projects. If a project defines a
function in shared_subcommands, that command will also be available in every
other pyrig-based project that depends on it (directly or transitively).
An example of this is pyrig's own version command, which is defined in pyrig.rig.cli.shared_subcommands
so that it is available in every project that uses pyrig.
So your project has already one command from the start that you can run:
uv run my-project version
# This will print smth like: my-project version 1.2.3
But if you run pyrig's version command directly,
you get the version of pyrig instead:
uv run pyrig version
# This will print smth like: pyrig version 12.3.4
To add a shared command, simply run pyrig mkcmd <command-name> --shared and
it will append the command skeleton to shared_subcommands (creating the
file if it does not exist).