typer icon indicating copy to clipboard operation
typer copied to clipboard

[BUG] single @app.command() doesn't require me to pass function name in CLI

Open fschlz opened this issue 2 years ago • 11 comments

If I only define one @app.command I cannot pass the corresponding function name as a command to the CLI

Instead of python main.py hello James

I have to use python main.py James

Which is inconsistent with the behavior of the package when I have more than one @app.command

fschlz avatar Aug 20 '21 11:08 fschlz

It is very much intended behaviour.

https://typer.tiangolo.com/tutorial/commands/one-or-multiple/

While it can be called inconsistent, it is more of pragrmatic decision. When you have just one command, why would you force user to write redundant commands, that don't accomplish anything?

If you still would like to force this behaviour, you can create hidden command, that does not do anything:

import typer

app = typer.Typer()


@app.command()
def main(name: str):
    typer.echo(name)


@app.command(hidden=True)
def secret():
    raise NotImplementedError()


if __name__ == "__main__":
    app()

sathoune avatar Aug 22 '21 06:08 sathoune

While it can be called inconsistent, it is more of pragrmatic decision. When you have just one command, why would you force user to write redundant commands, that don't accomplish anything?

For the sake of consistency.

Now I have to remember that the code behaves differently when I only have one app command function. I don't see why that would be considered pragmatic.

fschlz avatar Aug 23 '21 11:08 fschlz

I believe whole computer industry started to outsource tasks, so we, as humanity, don't have to perform them. Heck, I think the whole civilization exists so we can automate, delagate or optimize processes. This makes that we don't have to seek water, food or shelter every day and focus on making our lives better.

Every task can be optimized to be performed faster, easier and more deterministic in execution or outcome. I appreciate very much that I don't have to type my password after sudo command every time or use triple mouse click instead of double click. These decisions have drawbacks, the first security, the second - I don't know, hardware tearing, or my pointing finger would be stronger by clicking more.

I think that, whenever creating software, or any tool used by people it is important to focus on experience of the user. When the task requires three hands, it needs at least two people to be around. When customer has to go through too many screens in online shop, he might just abandon the purchase. Or when someone has to write two words instead of one, he will make typos more often or just won't remember the other word, so he will have to check documentation, help or write an email, which would take a lot more time than dropping redundant action.

Thus I consider this decision pragmatic.

sathoune avatar Aug 24 '21 21:08 sathoune

#243 is related

graue70 avatar Sep 03 '21 01:09 graue70

@fschlz, I +1 this issue. If we write a cli called sample that has two subcommands, list and get, we will need to invoke sample get to invoke get. Then if I remove the list, the "sample" CLI will only have get and we need invoke just sample instead of sample get. This behavior is strange.

To avoid having to change the caller, I will probably always write a subcommand called dummy. This is an unnecessary pain and I don't think it fits with @captainCapitalism philosophy either.

conao3 avatar Sep 04 '21 05:09 conao3

The documentation actually already gives you a solution to this case, without needing to create a dummy subcommand, but instead adding a callback.

https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#one-command-and-one-callback

While in the minimal example, adding a callback or a dummy subcommand seem the same, there is actually a practical benefit to using a callback. Having a callback lets you add documentation to your main command, as the next section in the docs demonstrates

https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#using-the-callback-to-document

So then you can run python main.py --help and get different documentation from python main.py mycommand --help.

jayqi avatar Sep 04 '21 17:09 jayqi

I am also of the opinion that this is not a bug. This is well defined and well-documented behaviour.

maybe there's room for improvement in the documentation, i'm not sure, but i think perhaps the "bug" label should be removed from this issue

alextremblay avatar Sep 13 '21 14:09 alextremblay

I think that bug label comes from just issue Template. (but the template is removed recentry)

conao3 avatar Sep 14 '21 01:09 conao3

I have this saved as a vscode snippet to document why an empty callback exists for the sake of future maintainers:

@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

I was unpleasantly surprised by the default behavior, and more surprised to discover there wasn't a Typer() option to force subcommands.

ajlive avatar May 31 '22 20:05 ajlive

I would like to chime in that there is a very good reason for why you want to do this, and that is if you intend on adding more subcommands in the future but have not yet done so. If you do intend on adding more subcommands, you want to require the subcommand being entered so that there is proper consistency and that users don't have a sudden change or breakage in how the CLI interacts.

I will also add that I struggled to find an option for doing this in Typer and this post helped me out a lot. (https://typer.tiangolo.com/tutorial/commands/one-or-multiple/#one-command-and-one-callback)

Edit: I just noticed @ajlive 's comment above, and completely agree 💪

mikegrima avatar Aug 01 '22 23:08 mikegrima

Adding my voice to this. This is a weird design choice. In many cases we start with a single command and then add more later. If someone depends on the single command behaviour, adding more commands later breaks the CLI for them.

I think a better design choice is adding a default tag to one of the commands. This would work with a single command as well as multiple commands if a command name is not given.

khaledh avatar Jun 28 '23 13:06 khaledh