Skip to content

SubCommands in a Single File

In some cases, it's possible that your application code needs to live on a single file.

You can still use the same ideas:

import typer

app = typer.Typer()
items_app = typer.Typer()
app.add_typer(items_app, name="items")
users_app = typer.Typer()
app.add_typer(users_app, name="users")


@items_app.command("create")
def items_create(item: str):
    print(f"Creating item: {item}")


@items_app.command("delete")
def items_delete(item: str):
    print(f"Deleting item: {item}")


@items_app.command("sell")
def items_sell(item: str):
    print(f"Selling item: {item}")


@users_app.command("create")
def users_create(user_name: str):
    print(f"Creating user: {user_name}")


@users_app.command("delete")
def users_delete(user_name: str):
    print(f"Deleting user: {user_name}")


if __name__ == "__main__":
    app()

There are several things to notice here...

Apps at the top

First, you can create typer.Typer() objects and add them to another one at the top.

It doesn't have to be done after creating the subcommands:

import typer

app = typer.Typer()
items_app = typer.Typer()
app.add_typer(items_app, name="items")
users_app = typer.Typer()
app.add_typer(users_app, name="users")


@items_app.command("create")
def items_create(item: str):
    print(f"Creating item: {item}")


@items_app.command("delete")
def items_delete(item: str):
    print(f"Deleting item: {item}")


@items_app.command("sell")
def items_sell(item: str):
    print(f"Selling item: {item}")


@users_app.command("create")
def users_create(user_name: str):
    print(f"Creating user: {user_name}")


@users_app.command("delete")
def users_delete(user_name: str):
    print(f"Deleting user: {user_name}")


if __name__ == "__main__":
    app()

You can add the commands (subcommands) to each typer.Typer() app later and it will still work.

Function names

As you now have subcommands like create for users and for items, you can no longer call the functions with just the name, like def create(), because they would overwrite each other.

So we use longer names:

import typer

app = typer.Typer()
items_app = typer.Typer()
app.add_typer(items_app, name="items")
users_app = typer.Typer()
app.add_typer(users_app, name="users")


@items_app.command("create")
def items_create(item: str):
    print(f"Creating item: {item}")


@items_app.command("delete")
def items_delete(item: str):
    print(f"Deleting item: {item}")


@items_app.command("sell")
def items_sell(item: str):
    print(f"Selling item: {item}")


@users_app.command("create")
def users_create(user_name: str):
    print(f"Creating user: {user_name}")


@users_app.command("delete")
def users_delete(user_name: str):
    print(f"Deleting user: {user_name}")


if __name__ == "__main__":
    app()

Command name

We are naming the functions with longer names so that they don't overwrite each other.

But we still want the subcommands to be create, delete, etc.

To call them like:

fast →python main.py items create
restart ↻

instead of:

fast →python main.py items items-create
restart ↻

So we pass the name we want to use for each subcommand as the function argument to the decorator:

import typer

app = typer.Typer()
items_app = typer.Typer()
app.add_typer(items_app, name="items")
users_app = typer.Typer()
app.add_typer(users_app, name="users")


@items_app.command("create")
def items_create(item: str):
    print(f"Creating item: {item}")


@items_app.command("delete")
def items_delete(item: str):
    print(f"Deleting item: {item}")


@items_app.command("sell")
def items_sell(item: str):
    print(f"Selling item: {item}")


@users_app.command("create")
def users_create(user_name: str):
    print(f"Creating user: {user_name}")


@users_app.command("delete")
def users_delete(user_name: str):
    print(f"Deleting user: {user_name}")


if __name__ == "__main__":
    app()

Check it

It still works the same:

fast →python main.py --help
Usage: main.py [OPTIONS] COMMAND [ARGS]...

Options:
--install-completion Install completion for the current shell.
--show-completion Show completion for the current shell, to copy it or
customize the installation.
--help Show this message and exit.

Commands:
items
users

restart ↻

Check the items command:

fast →python main.py items --help
Usage: main.py items [OPTIONS] COMMAND [ARGS]...

Options:
--help Show this message and exit.

Commands:
create
delete
sell

python main.py items create Wand
Creating item: Wand

python main.py items sell Vase
Selling item: Vase

restart ↻

And the same for the users command:

fast →python main.py users --help
Usage: main.py users [OPTIONS] COMMAND [ARGS]...

Options:
--help Show this message and exit.

Commands:
create
delete

python main.py users create Camila
Creating user: Camila

restart ↻
Was this page helpful?