Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
fschlz opened this issue Aug 20, 2021 · 11 comments
Open
Labels
bug Something isn't working

Comments

@fschlz
Copy link

fschlz commented Aug 20, 2021

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 fschlz added the bug Something isn't working label Aug 20, 2021
@sathoune
Copy link

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()

@fschlz
Copy link
Author

fschlz commented Aug 23, 2021

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.

@sathoune
Copy link

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.

@graue70
Copy link
Contributor

graue70 commented Sep 3, 2021

#243 is related

@conao3
Copy link

conao3 commented Sep 4, 2021

@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.

@jayqi
Copy link

jayqi commented Sep 4, 2021

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.

@alextremblay
Copy link

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

@conao3
Copy link

conao3 commented Sep 14, 2021

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

@ajlive
Copy link

ajlive commented May 31, 2022

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.

@mikegrima
Copy link

mikegrima commented Aug 1, 2022

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 💪

@khaledh
Copy link

khaledh commented Jun 28, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants