In our CLI, all commands are grouped under a single command group. This allowed us to implement some behavior that needed to be executed for each command. One part of that is the exception handling.
Our entry point looks something like this:
@click.group()
@click.pass_context
def entry_point(ctx):
ctx.obj = {"example": "This could be the configuration"}
We use it to run global code, e.g. configure the context
, but you can also define an empty method that does nothing. Other commands can be added to this command group either by using the @entry_point.command()
decorator or entry_point.add_command(cmd)
.
For the exception handling, we wrap the entry_point
in another method that handles the exceptions:
def safe_entry_point():
try:
entry_point()
except Exception as e:
click.echo(e)
In setup.py
, we configure the entry point for the CLI and point it to the wrapper:
entry_points={
'console_scripts': [
'cli = my.package:safe_entry_point'
]
}
The commands of the CLI can be executed through its command group: e.g. cli command
.
There might be more elegant solutions out there, but this is how we solved it. While it introduces a command group as the highest-level element in your CLI, but it allows us do handle all exceptions in a single place without the need to duplicate our error handling in each and every command.