typer icon indicating copy to clipboard operation
typer copied to clipboard

[QUESTION] why replace "_" with "-" in command name?

Open bloodynumen opened this issue 3 years ago โ€ข 14 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the Typer documentation, with the integrated search.
  • [X] I already searched in Google "How to X in Typer" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to Typer but to Click.

Commit to Help

  • [X] I commit to help with one of those options ๐Ÿ‘†

Example Code

from typing import Optional

import typer

app = typer.Typer()


@app.command()
def hello_test(name: Optional[str] = None):
    if name:
        typer.echo(f"Hello {name}")
    else:
        typer.echo("Hello World!")

if __name__ == "__main__":
    app()

Description

expect: python main.py hello_test --name world actually: python main.py hello-test --name world

I found the "_" in command name is replaced with "-". source code https://github.com/tiangolo/typer/blob/master/typer/main.py#L390

why do this?

Thank u

Operating System

macOS

Operating System Details

No response

Typer Version

0.4.0

Python Version

3.9.7

Additional Context

No response

bloodynumen avatar Nov 19 '21 14:11 bloodynumen

This is probably just a design choice based around natural CLI convention. You're usually gonna find dashes in commands in any CLI, not underscores. If you want to keep the underscore, you can just specify the command name manually in the app.command().

daddycocoaman avatar Dec 31 '21 21:12 daddycocoaman

This type of undocumented behavior is why I have decided not to use Typer. I like a lot of things about the package, but it's not worth the learning curve of digging through the code when something doesn't work as expected.

mbopfNIH avatar May 23 '22 12:05 mbopfNIH

I guess that helps

targhs avatar Jun 10 '22 21:06 targhs

In fact, this is something that comes from the "click" package which typer uses as a base. If it helps, it comes from here:

https://github.com/pallets/click/blob/dc918b48fb9006be683a684b42cc7496ad649b83/src/click/core.py#L2633

manueldeprada avatar Jul 31 '22 12:07 manueldeprada

Yeah this is pretty annoying. Is there any way to disable this behaviour? There doesn't seem to be anything in typer.Option(). In fact I couldn't find any reference documentation at all...?

Timmmm avatar Aug 21 '23 13:08 Timmmm

Yeah this is pretty annoying. Is there any way to disable this behaviour? There doesn't seem to be anything in typer.Option(). In fact I couldn't find any reference documentation at all...?

I donโ€™t think so, since it comes from click. I switched to Python Fire by google.

manueldeprada avatar Aug 21 '23 14:08 manueldeprada

Ok this comes from get_command_name().

You can fix it like this:

typer.main.get_command_name = lambda name: name

I suggest an annotation on def main() to allow you to configure whether or not this happens.

Also note for bool options you'll get --no-foo_bar which is a bit weird but whatever.

Timmmm avatar Aug 21 '23 14:08 Timmmm

I switched to Python Fire by google.

Ah I hadn't heard of that. Had a look but it seems like it has a slightly different focus and also doesn't support type hints which is like 90% of the reason for using Typer. I'll stick with my get_command_name hack for now I reckon.

Timmmm avatar Aug 21 '23 20:08 Timmmm

Ok this comes from get_command_name().

You can fix it like this:

typer.main.get_command_name = lambda name: name

I suggest an annotation on def main() to allow you to configure whether or not this happens.

Also note for bool options you'll get --no-foo_bar which is a bit weird but whatever.

Hmm interesting. Can you check if it also works for option names? I mean like --cool_option gets transformed into cool-option? Thanks :)

manueldeprada avatar Aug 21 '23 20:08 manueldeprada

Hmm interesting. Can you check if it also works for option names? I mean like --cool_option gets transformed into cool-option? Thanks :)

Yep that's how I'm using it.

#!/usr/bin/env python3

import typer
from typing_extensions import Annotated

typer.main.get_command_name = lambda name: name

def main(foo_bar: Annotated[int, typer.Option(help="Do a thing.")]):
    return 0

if __name__ == "__main__":
    typer.run(main)
โฏ ./test.py --help
                                                                                                             
 Usage: test.py [OPTIONS]                                                                                    
                                                                                                             
โ•ญโ”€ Options โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ *  --foo_bar        INTEGER  Do a thing. [default: None] [required]                                       โ”‚
โ”‚    --help                    Show this message and exit.                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Timmmm avatar Aug 22 '23 06:08 Timmmm

ะฅะผ ั†ั–ะบะฐะฒะพ. ะงะธ ะผะพะถะตั‚ะต ะฒะธ ะฟะตั€ะตะฒั–ั€ะธั‚ะธ, ั‡ะธ ั†ะต ั‚ะฐะบะพะถ ะฟั€ะฐั†ัŽั” ะดะปั ะฝะฐะทะฒ ะฟะฐั€ะฐะผะตั‚ั€ั–ะฒ? ะฏ ะผะฐัŽ ะฝะฐ ัƒะฒะฐะทั–, ัะบ --cool_option ะฟะตั€ะตั‚ะฒะพั€ัŽั”ั‚ัŒัั ะฝะฐ cool-option? ะ”ัะบัƒัŽ :)

ะขะฐะบ, ั ั†ะธะผ ะบะพั€ะธัั‚ัƒัŽัั.

#!/usr/bin/env python3

import typer
from typing_extensions import Annotated

typer.main.get_command_name = lambda name: name

def main(foo_bar: Annotated[int, typer.Option(help="Do a thing.")]):
    return 0

if __name__ == "__main__":
    typer.run(main)
โฏ ./test.py --help
                                                                                                             
 Usage: test.py [OPTIONS]                                                                                    
                                                                                                             
โ•ญโ”€ Options โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ *  --foo_bar        INTEGER  Do a thing. [default: None] [required]                                       โ”‚
โ”‚    --help                    Show this message and exit.                                                  โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Thanks, you saved me a lot of time!

VladikaAndrii avatar Sep 13 '23 11:09 VladikaAndrii