Commands, groups and aliases¶
Everything under commands becomes a command of your CLI. The key decides where the command lives
and what it is called; the value decides what it does.
The snippets on this page come from one manifest, shown in full at the end.
Three ways to write a command¶
# 1. A string: the whole value is the run script
ping: print("pong")
# 2. A list: each item is a line of the run script
status:
- print("checking...")
- $ echo "all good"
# 3. A mapping: the full form
greet:
help: Greet a customer
params:
- name: str = "friend"
run: |
print(f"Welcome, {name}!")
Use the short forms for one-liners and the mapping when you need help, params or anything else.
The keys of the mapping are listed in the manifest reference.
Command names may contain letters, digits, - and _.
Groups¶
A dot in the key puts the command in a group. Groups are created as needed and can be nested.
# A dot nests a command inside a group: `shop orders list`
orders.create:
help: Create an order
params:
- item: str!
run: print(f"created order for {item}")
orders.ship:
help: Ship an order
params:
- number: int!
run: print(f"shipped order {number}")
# Groups nest as deep as you like: `shop stock warehouse count`
stock.warehouse.count: print("42 items")
# A command with help and no run script sets the help text of the group
orders:
help: Manage customer orders
$ cli run commands.yaml orders create book
created order for book
$ cli run commands.yaml stock warehouse count
42 items
$ cli run commands.yaml -- orders --help
...
╭─ Commands ─────────────────────────────────────────────────────────────────╮
│ create Create an order │
│ ship Ship an order │
│ list List all orders │
╰────────────────────────────────────────────────────────────────────────────╯
To describe a group, add an entry with the group's name that has help and no run, like orders
above. A name is either a group or a command: if orders had a run script while orders.create
exists, the group would take the name and the script could not be reached.
Aliases¶
# `shop customers add` and `shop customers new` run the same code
customers.add|new:
help: Add a customer
params:
- name: str!
run: print(f"added {name}")
# The aliases field does the same without touching the key
version-info:
help: Show build details
aliases: [vi]
run: print("build 7")
|in the key adds aliases to the last part of the name:customers.add|newgivescustomers addandcustomers new.- The
aliaseslist does the same from inside the command.
Aliases are hidden from --help. When a manifest defines aliases in its keys, the CLI gets an
--aliases option that lists them:
One command for every group¶
A key that starts with (*) is added to every group. Inside that command, {(*)} is replaced with
the group's name, in help, run, pre_run, post_run and params.
# (*) adds this command to every group; {(*)} is replaced by the group name
(*).list:
help: List all {(*)}
params:
- --limit|-l: int = 10
run: print(f"listing {limit} {(*)}")
$ cli run commands.yaml orders list
listing 10 orders
$ cli run commands.yaml -- customers list -l 3
listing 3 customers
Run scripts¶
run is Python. Write it as a block (run: |) or as a list of lines. Lines that start with $ are
shell commands, described in Shell commands.
Two hooks wrap the script. pre_run runs before run and post_run after it, in the same function,
so all three share variables.
deploy:
help: Deploy the shop
pre_run: print("1. pre_run")
run: print("2. run")
post_run: print("3. post_run")
Hooks are most useful together with command templates, which let several commands share them.
To stop a command with an exit code, raise typer.Exit:
Help text¶
help on a command is shown in the command list and at the top of the command's own --help.
Because run is the body of a Python function, a docstring on its first line works as well:
Command settings¶
config passes extra settings to Typer for one command.
migrate:
help: Run the old migration tool
run: print("migrating")
config:
deprecated: true
hidden: true
epilog: Use `shop deploy` instead.
| Key | Effect |
|---|---|
hidden |
Leave the command out of --help. |
deprecated |
Mark the command as deprecated and print a warning when it runs. |
epilog |
Text shown at the end of the command's help. |
short_help |
Text for the command list, when it should differ from help. |
no_args_is_help |
Show help when the command is called without arguments. |
context_settings |
Click context settings, for example help_option_names. |
All keys are in the manifest reference.
The complete example¶
name: shop
version: 0.1.0
help: Groups, aliases and command options
cli_options:
add_completion: false
no_args_is_help: true
commands:
# 1. A string: the whole value is the run script
ping: print("pong")
# 2. A list: each item is a line of the run script
status:
- print("checking...")
- $ echo "all good"
# 3. A mapping: the full form
greet:
help: Greet a customer
params:
- name: str = "friend"
run: |
print(f"Welcome, {name}!")
# A dot nests a command inside a group: `shop orders list`
orders.create:
help: Create an order
params:
- item: str!
run: print(f"created order for {item}")
orders.ship:
help: Ship an order
params:
- number: int!
run: print(f"shipped order {number}")
# Groups nest as deep as you like: `shop stock warehouse count`
stock.warehouse.count: print("42 items")
# A command with help and no run script sets the help text of the group
orders:
help: Manage customer orders
# `shop customers add` and `shop customers new` run the same code
customers.add|new:
help: Add a customer
params:
- name: str!
run: print(f"added {name}")
# The aliases field does the same without touching the key
version-info:
help: Show build details
aliases: [vi]
run: print("build 7")
# (*) adds this command to every group; {(*)} is replaced by the group name
(*).list:
help: List all {(*)}
params:
- --limit|-l: int = 10
run: print(f"listing {limit} {(*)}")
deploy:
help: Deploy the shop
pre_run: print("1. pre_run")
run: print("2. run")
post_run: print("3. post_run")
migrate:
help: Run the old migration tool
run: print("migrating")
config:
deprecated: true
hidden: true
epilog: Use `shop deploy` instead.
about:
run: |
"""Show what this CLI is for"""
print("A demo shop")
tests:
- ping: assert result.output == "pong\n"
- greet: assert result.output == "Welcome, friend!\n"
- orders create book: assert result.output == "created order for book\n"
- orders ship 7: assert result.output == "shipped order 7\n"
- stock warehouse count: assert result.output == "42 items\n"
- orders --help: assert "Manage customer orders" in result.output
- customers new Ada: assert result.output == "added Ada\n"
- vi: assert result.output == "build 7\n"
- orders list: assert result.output == "listing 10 orders\n"
- customers list -l 3: assert result.output == "listing 3 customers\n"
- orders list --help: assert "List all orders" in result.output
- deploy: assert result.output == "1. pre_run\n2. run\n3. post_run\n"
- migrate: assert "migrating" in result.output
- --help: assert "migrate" not in result.output
- about --help: assert "Show what this CLI is for" in result.output
- --aliases: assert "customers.add" in result.output