Commands
There are two different ways of registering functions:
app.default
- Registers an action for when no registered command is provided. This was previously demonstrated in Getting Started.A sub-app cannot be registered with
app.default
. If nodefault
command is registered, Cyclopts will display the help-page.app.command
- Registers a function orApp
as a command.
This section will detail how to use the @app.command
decorator.
Registering a Command
The @app.command
decorator adds a command to a Cyclopts application.
from cyclopts import App
app = App()
@app.command
def fizz(n: int):
print(f"FIZZ: {n}")
@app.command
def buzz(n: int):
print(f"BUZZ: {n}")
app()
We can now control which command runs from the CLI:
$ my-script fizz 3
FIZZ: 3
$ my-script buzz 4
BUZZ: 4
$ my-script fuzz
╭─ Error ────────────────────────────────────────────────────────────────────╮
│ Unknown command "fuzz". Did you mean "fizz"? │
╰────────────────────────────────────────────────────────────────────────────╯
Registering a SubCommand
The app.command
method can also register another Cyclopts App
as a command.
from cyclopts import App
app = App()
sub_app = App(name="foo") # "foo" would be a better variable name than "sub_app".
# "sub_app" in this example emphasizes the name comes from name="foo".
app.command(sub_app) # Registers sub_app to command "foo"
# Or, as a one-liner: app.command(sub_app := App(name="foo"))
@sub_app.command
def bar(n: int):
print(f"BAR: {n}")
# Alternatively, access subapps from app like a dictionary.
@app["foo"].command
def baz(n: int):
print(f"BAZ: {n}")
app()
$ my-script foo bar 3
BAR: 3
$ my-script foo baz 4
BAZ: 4
The subcommand may have their own registered default
action.
Cyclopts's command structure is fully recursive.
Changing Command Name
By default, commands are registered to the python function's name with underscores replaced with hyphens.
Any leading or trailing underscores will be stripped.
For example, the function _foo_bar()
will become the command foo-bar
.
This renaming is done because CLI programs generally tend to use hyphens instead of underscores.
The name transform can be configured by App.name_transform
.
For example, to make CLI command names be identical to their python function name counterparts, we can configure App
as follows:
from cyclopts import App
app = App(name_transform=lambda s: s)
@app.command
def foo_bar(): # will now be "foo_bar" instead of "foo-bar"
print("running function foo_bar")
app()
$ my-script foo_bar
running function foo_bar
Alternatively, the name can be manually changed in the @app.command
decorator.
Manually set names are not subject to App.name_transform
.
from cyclopts import App
app = App()
@app.command(name="bar")
def foo(): # function name will NOT be used.
print("Hello World!")
app()
$ my-script bar
Hello World!
Adding Help
There are a few ways to add a help string to a command:
If the function has a docstring, the short description will be used as the help string for the command. This is generally the preferred method of providing help strings.
If the registered command is a sub app, the sub app's
help
field will be used.sub_app = App(name="foo", help="Help text for foo.") app.command(sub_app)
The
help
field of@app.command
. If provided, the docstring or subapp help field will not be used.from cyclopts import App app = App() @app.command def foo(): """Help string for foo.""" pass @app.command(help="Help string for bar.") def bar(): """This got overridden.""" app()
$ my-script --help ╭─ Commands ────────────────────────────────────────────────────────────╮ │ bar Help string for bar. │ │ foo Help string for foo. │ │ --help,-h Display this message and exit. │ │ --version Display application version. │ ╰───────────────────────────────────────────────────────────────────────╯
Async
Cyclopts also works with async commands:
import asyncio
from cyclopts import App
app = App()
@app.command
async def foo():
await asyncio.sleep(10)
app()
Decorated Function Details
Cyclopts does not modify the decorated function in any way. The returned function is the exact same function being decorated and can be used exactly as if it were not decorated by Cyclopts.