Default Command
Typer has an annoying design quirk where if you register a single command, it won't expect you to provide the command name in the CLI. For example:
typer_app = typer.Typer()
@typer_app.command()
def foo():
print("FOO")
typer_app([], standalone_mode=False)
# FOO
typer_app(["foo"], standalone_mode=False)
# raises exception: Got unexpected extra argument (foo)
Once you add a second command, then the CLI expects the command to be provided:
typer_app(["foo"], standalone_mode=False)
# FOO
typer_app(["bar"], standalone_mode=False)
# BAR
This behavior catches many people off guard.
If you want a single command, you have to unintuitively declare a callback
.
Github user ajlive's callback solution is copied below.
@app.callback()
def dummy_to_force_subcommand() -> None:
"""
This function exists because Typer won't let you force a single subcommand.
Since we know we will add other subcommands in the future and don't want to
break the interface, we have to use this workaround.
Delete this when a second subcommand is added.
"""
pass
To avoid this confusion, Cyclopts has two ways of registering a function:
@app.command
- Register a function as a command.@app.default
- Invoked if no registered command can be parsed from the CLI.
cyclopts_app = cyclopts.App()
@cyclopts_app.command
def foo():
print("FOO")
cyclopts_app(["foo"])
# FOO