Typer, build great CLIs. Easy to code. Based on Python type hints.

Overview

Typer

Typer, build great CLIs. Easy to code. Based on Python type hints.

Test Publish Coverage Package version


Documentation: https://typer.tiangolo.com

Source Code: https://github.com/tiangolo/typer


Typer is a library for building CLI applications that users will love using and developers will love creating. Based on Python 3.6+ type hints.

The key features are:

  • Intuitive to write: Great editor support. Completion everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.
  • Easy to use: It's easy to use for the final users. Automatic help, and automatic completion for all shells.
  • Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
  • Start simple: The simplest example adds only 2 lines of code to your app: 1 import, 1 function call.
  • Grow large: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.

FastAPI of CLIs

Typer is FastAPI's little sibling.

And it's intended to be the FastAPI of CLIs.

Requirements

Python 3.6+

Typer stands on the shoulders of a giant. Its only internal dependency is Click.

Installation

$ pip install typer
---> 100%
Successfully installed typer

Example

The absolute minimum

  • Create a file main.py with:
import typer


def main(name: str):
    typer.echo(f"Hello {name}")


if __name__ == "__main__":
    typer.run(main)

Run it

Run your application:

// Run your application
$ python main.py

// You get a nice error, you are missing NAME
Usage: main.py [OPTIONS] NAME
Try "main.py --help" for help.

Error: Missing argument 'NAME'.

// You get a --help for free
$ python main.py --help

Usage: main.py [OPTIONS] NAME

Arguments:
  NAME  [required]

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.

// When you create a package you get ✨ auto-completion ✨ for free, installed with --install-completion

// Now pass the NAME argument
$ python main.py Camila

Hello Camila

// It works! 🎉

Note: auto-completion works when you create a Python package and run it with --install-completion or when you use Typer CLI.

Example upgrade

This was the simplest example possible.

Now let's see one a bit more complex.

An example with two subcommands

Modify the file main.py.

Create a typer.Typer() app, and create two subcommands with their parameters.

import typer

app = typer.Typer()


@app.command()
def hello(name: str):
    typer.echo(f"Hello {name}")


@app.command()
def goodbye(name: str, formal: bool = False):
    if formal:
        typer.echo(f"Goodbye Ms. {name}. Have a good day.")
    else:
        typer.echo(f"Bye {name}!")


if __name__ == "__main__":
    app()

And that will:

  • Explicitly create a typer.Typer app.
    • The previous typer.run actually creates one implicitly for you.
  • Add two subcommands with @app.command().
  • Execute the app() itself, as if it was a function (instead of typer.run).

Run the upgraded example

// Check the --help
$ 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:
  goodbye
  hello

// You have 2 subcommands (the 2 functions): goodbye and hello

// Now get the --help for hello

$ python main.py hello --help

Usage: main.py hello [OPTIONS] NAME

Arguments:
  NAME  [required]

Options:
  --help  Show this message and exit.

// And now get the --help for goodbye

$ python main.py goodbye --help

Usage: main.py goodbye [OPTIONS] NAME

Arguments:
  NAME  [required]

Options:
  --formal / --no-formal  [default: False]
  --help                  Show this message and exit.

// Automatic --formal and --no-formal for the bool option 🎉

// And if you use it with the hello command

$ python main.py hello Camila

Hello Camila

// And with the goodbye command

$ python main.py goodbye Camila

Bye Camila!

// And with --formal

$ python main.py goodbye --formal Camila

Goodbye Ms. Camila. Have a good day.

Recap

In summary, you declare once the types of parameters (CLI arguments and CLI options) as function parameters.

You do that with standard modern Python types.

You don't have to learn a new syntax, the methods or classes of a specific library, etc.

Just standard Python 3.6+.

For example, for an int:

total: int

or for a bool flag:

force: bool

And similarly for files, paths, enums (choices), etc. And there are tools to create groups of subcommands, add metadata, extra validation, etc.

You get: great editor support, including completion and type checks everywhere.

Your users get: automatic --help, auto-completion in their terminal (Bash, Zsh, Fish, PowerShell) when they install your package or when using Typer CLI.

For a more complete example including more features, see the Tutorial - User Guide.

Optional Dependencies

Typer uses Click internally. That's the only dependency.

But you can also install extras:

  • colorama: and Click will automatically use it to make sure your terminal's colors always work correctly, even in Windows.
    • Then you can use any tool you want to output your terminal's colors in all the systems, including the integrated typer.style() and typer.secho() (provided by Click).
    • Or any other tool, e.g. wasabi, blessings.
  • shellingham: and Typer will automatically detect the current shell when installing completion.
    • With shellingham you can just use --install-completion.
    • Without shellingham, you have to pass the name of the shell to install completion for, e.g. --install-completion bash.

You can install typer with colorama and shellingham with pip install typer[all].

Other tools and plug-ins

Click has many plug-ins available that you can use. And there are many tools that help with command line applications that you can use as well, even if they are not related to Typer or Click.

For example:

  • click-spinner: to show the user that you are loading data. A Click plug-in.
    • There are several other Click plug-ins at click-contrib that you can explore.
  • tabulate: to automatically display tabular data nicely. Independent of Click or Typer.
  • tqdm: a fast, extensible progress bar, alternative to Typer's own typer.progressbar().
  • etc... you can re-use many of the great available tools for building CLIs.

License

This project is licensed under the terms of the MIT license.

Issues
  • [QUESTION] Dependency Injection

    [QUESTION] Dependency Injection

    First check

    • [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 searched in Google "How to X in Click" and didn't find any information.

    First of all, thank you for your amazing tools, it helps my team and I to build great products !

    Description

    How can I inject a Database connection to a "cli function" ?

    I was looking for a mecanism like Depends in FastAPI (https://fastapi.tiangolo.com/tutorial/dependencies/)

    Additional context

    I'm trying to create a cli which read files and insert them to a database but one of my subcommands is depending of a Database connection.

    For the moment I've used:

    save_app = typer.Typer()
    
    
    def get_db():
        typer.echo("Initializing database")
        db = VerticaDB(
            host=conf.get_vertica_host(),
            port=conf.get_vertica_port(),
            user=conf.get_vertica_user(),
            password=conf.get_vertica_password(),
            database=conf.get_vertica_database()
        )
        return db
    
    
    @save_app.command("save")
    def ingest_snitch_file(
            path_to_log_file: Path = typer.Option(
                ...,
                exists=True,
                readable=True,
                envvar='PATH_TO_SNITCH_FILE'
            ),
            db=typer.Option(
                hidden=True,
                default=get_db()
            )
    ):
        """
        Ingest snitch files to Database
        """
        snitch = Snitch(
            db=db,
            path_to_snitch=path_to_log_file,
            table_schema=conf.get_vertica_table_schema(),
            table_name=conf.get_vertica_table_name()
        )
        snitch.insert_log_to_database()
    
    question 
    opened by Leletir 14
  • [QUESTION] How to use Typer within Objects

    [QUESTION] How to use Typer within Objects

    Hello,

    I already used Typer for a few short CLIs but now I'd like to use it for a bigger, object-oriented project. I thought I find a way to use it correctly, but I'm getting errors related to the "self" argument.

    My code looks like this:

    main_menu.py

    class MainMenu:
        typer_app = typer.Typer()
        typer_app.add_typer(TournamentMenu.typer_app, name="tournament")
    
        def __init__(self):
            self.typer_app()
            self.tournament_handler = None
            self.print_menu()
            self.user_selection()
    
        def print_menu(self):
            number = typer.style("1. ", bold=True)
            typer.echo(number + "Tournois")
    
            number = typer.style("2. ", bold=True)
            typer.echo(number + "Gérer les joueurs")
    
        def user_selection(self):
            selection = typer.prompt("Entrez votre sélection: ")
            typer.echo("\n")
    
            if selection == "1":
                self.open_tournament_menu()
            else:
                self.user_selection()
    
        def open_tournament_menu(self):
            TournamentMenu()
    

    tournament_menu.py

    class TournamentMenu:
        typer_app = typer.Typer()
    
        def __init__(self):
            self.typer_app()
            self.print_menu()
            self.user_selection()
    
        def print_menu(self):
            number = typer.style("1. ", bold=True)
            typer.echo(number + "Commencer un nouveau tournoi")
    
            number = typer.style("2. ", bold=True)
            typer.echo(number + "Charger un tournoi")
    
        def user_selection(self):
            selection = typer.prompt("Entrez votre sélection: ")
    
            if selection == "1":
                self.create_new_tournament()
            else:
                self.user_selection()
    
        @typer_app.command("new")
        def create_new_tournament(self=None):
            NewTournamentMenu()
    

    new_tournament_menu.py

    class NewTournamentMenu:
        typer_app = typer.Typer()
    
        @typer_app.command()
        def __init__(self):
            self.typer_app()
            self.print_menu()
            self.user_selection()
    
        def print_menu(self):
            number = typer.style("1. ", bold=True)
            typer.echo(number + "Commencer un nouveau tournoi")
    
            number = typer.style("2. ", bold=True)
            typer.echo(number + "Charger un tournoi")
    
        def user_selection(self):
            selection = typer.prompt("Entrez votre sélection: ")
    
            if selection == "1":
                pass
            else:
                self.user_selection()
    

    But for example with python main.py tournament newI'm getting:

    Usage: dev.py [OPTIONS] SELF
    Try 'dev.py --help' for help.
    
    Error: Got unexpected extra argument (new)
    

    So, is it possible to use typer in this kind of object oriented situation ? What am I missing ?

    question 
    opened by PabloLec 12
  • running typer cli command from python code

    running typer cli command from python code

    How can i trigger/run typer cli specific command from python code. I guess i need to emulate command line arguments some where but not sure. Can you please help on this?

    Cli: python main.py goodbye --formal Camila

    From Code: i want to run specific command based on my need. how do i pass command line arguments, some thing like: typer_app( "goodbye --formal Camila" )

    question answered 
    opened by blnprasad 11
  • [QUESTION] using python-rich with Typer

    [QUESTION] using python-rich with Typer

    First check

    • [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 searched in Google "How to X in Click" and didn't find any information.

    Description

    How can I use python-rich with Typer ?

    Eg.

    from rich.console import Console
    
    console = Console()
    
    @app.command()
    def version() -> None:
        """Show project Version."""
        # typer.secho(f"project Version: {__version__}", fg=typer.colors.BRIGHT_GREEN)
    
        console.print(f"project Version: {__version__}", style="bold green")
    

    output:

    project Version: 0.0.1
    

    the problem that am facing is in test mode

    runner = CliRunner()
    
    def test_version_succeeds() -> None:
        """It exits with a status code of zero."""
        result = runner.invoke(app)
        assert result.exit_code == 0
        assert "project" in result.stdout
    

    output:

    FAILED tests/test_manage.py::test_version_succeeds - AssertionError: assert 'project' in ''
    

    So is there a way to make them work together ?

    question 
    opened by Mohamed-Kaizen 9
  • [QUESTION] How to add short option

    [QUESTION] How to add short option "-h" to "--help" callback

    First check

    • [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 searched in Google "How to X in Click" and didn't find any information.

    Description

    How can I add a short option "-h" to the existing "--help" callback?

    question 
    opened by JeromeK13 9
  • [QUESTION] mypy complaining about missing attributes when importing typer

    [QUESTION] mypy complaining about missing attributes when importing typer

    First check

    • [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 searched in Google "How to X in Click" and didn't find any information.

    Description

    I am trying to use the type types get parsed in mypy. From my experience with mypy, the packages are either supported "out of the box" or not at all and must be ignored.

    It's a different issue than https://github.com/tiangolo/typer/issues/53

    I am not sure if I am doing something wrong or this is a bug.

    I am using mypy==0.770 on Python 3.7

    Thanks,

    Jean-Martin

    Additional context

    mypy command:

    mypy --show-error-codes --strict some_script.py
    

    mypy error (the line number will not match truncate script below)

    some_script.py:10: error: Module has no attribute "Typer"  [attr-defined]
    some_script.py:13: error: Untyped decorator makes function "main" untyped  [misc]
    some_script.py:14: error: Function is missing a return type annotation  [no-untyped-def]
    some_script.py:18: error: Module has no attribute "Option"  [attr-defined]
    some_script.py:19: error: Module has no attribute "Option"  [attr-defined]
    some_script.py:20: error: Module has no attribute "Option"  [attr-defined]
    some_script.py:21: error: Module has no attribute "Option"  [attr-defined]
    some_script.py:31: error: Module has no attribute "run"  [attr-defined]
    

    mypy config

    [mypy]
    namespace_packages = true
    
    # The following 3rd party dependencies don't have type hints. We ignore them one by one instead of
    # blindly running with --ignore-missing-imports.
    
    [mypy-typer]
    
    [mypy-setuptools]
    ignore_missing_imports = True
    

    Truncated code:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    import json
    
    import typer
    import yaml
    
    app = typer.Typer()
    
    
    @app.command(
        help="Something."
    )
    def main(
        option_a: str = typer.Option(...),
        option_b: str = typer.Option(...),
        option_c: str = typer.Option(...),
        option_d: str = typer.Option(...),
    ) -> None:
        # Non problematic code
        ...
    
    
    if __name__ == "__main__":
        typer.run(main)
    

    Workaround

    https://github.com/tiangolo/typer/issues/112#issuecomment-648347626

    question answered 
    opened by j-martin 8
  • [FEATURE] Adding Typer to custom package using entry points

    [FEATURE] Adding Typer to custom package using entry points

    Wuhuu finally started using Typer and very excited about it.

    I went ahead and used the most simple example

    import typer
    
    def main(name: str):
        typer.echo(f"Hello {name}")
    
    
    if __name__ == "__main__":
        typer.run(main)
    

    which works just fine obviously. But I'd like to expose my custom package with CLI using Typer so I made a setup.py with

    from setuptools import setup
    
    setup(
        name="my_package",
        entry_points={
            "console_scripts": ["hello = my_package.cli:main"],
        },
    )
    

    Then I can call the command using hello in a terminal BUT it doesn't carry over any positional arguments. Maybe you could add some about entry points integration in the docs?

    enhancement 
    opened by mr-bjerre 8
  • [BUG] TypeError is raised if argument is capitalized

    [BUG] TypeError is raised if argument is capitalized

    Describe the bug

    If the "entry" function (the one decorated with typer.Typer.command or the one passed to typer.run) expects a capitalized argument, a TypeError will be raised (TypeError: () got an unexpected keyword argument '')

    To Reproduce

    • Create a file main.py with:
    import typer
    
    app = typer.Typer()
    
    @app.command()
    def hello(nAme: str):
        typer.echo(f"Hello {nAme}")
    
    
    if __name__ == "__main__":
        app()
    
    • Call it with:
    python main.py GodSaveTheDoge
    
    • It outputs:
    Traceback (most recent call last):
      File "githubExample.py", line 11, in <module>
        app()
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/typer/main.py", line 214, in __call__
        return get_command(self)(*args, **kwargs)
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/click/core.py", line 829, in __call__
        return self.main(*args, **kwargs)
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/click/core.py", line 782, in main
        rv = self.invoke(ctx)
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/click/core.py", line 610, in invoke
        return callback(*args, **kwargs)
      File "/data/data/com.termux/files/usr/lib/python3.8/site-packages/typer/main.py", line 497, in wrapper
        return callback(**use_params)  # type: ignore
    TypeError: hello() got an unexpected keyword argument 'name'
    
    • But I expected it to output:
    Hello GodSaveTheDoge
    

    Expected behavior

    I expected the function to be called with the capitalized version instead.

    Environment

    • OS: Android
    • Typer Version: 0.3.2
    • Python version: 3.8.0
    bug 
    opened by GodSaveTheDoge 8
  • ✨ Add support for Click 8 while keeping compatibility with Click 7

    ✨ Add support for Click 8 while keeping compatibility with Click 7

    ✨ Add support for Click 8 while keeping support for Click 7

    opened by tiangolo 8
  • [FEATURE] Set a defaut command in multiple commands

    [FEATURE] Set a defaut command in multiple commands

    I wanna to be able to set a default command when I have multiples commands. For example, with:

    import typer
    
    app = typer.Typer()
    
    
    @app.command()
    def hello(name: str):
        typer.echo(f"Hello {name}")
    
    
    @app.command()
    def goodbye(name: str, formal: bool = False):
        if formal:
            typer.echo(f"Goodbye Ms. {name}. Have a good day.")
        else:
            typer.echo(f"Bye {name}!")
    
    
    if __name__ == "__main__":
        app()
    

    I would like to have some way of being able to call it without specifying the command, calling a default command (maybe with something like @app.command(default=True) like this:

    $ python main.py Hiro
    Hello Hiro
    
    $ python main.py helo Hiro  # This also should work
    Hello Hiro
    
    enhancement 
    opened by lbellomo 8
  • Specifying help for arguments & options in function docstrings

    Specifying help for arguments & options in function docstrings

    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

    This is the current way to add help text for arguments (and similarly for options).

    import typer
    
    
    def main(name: str = typer.Argument(..., help="The name of the user to greet")):
        """
        Say hi to NAME very gently, like Dirk.
        """
        typer.echo(f"Hello {name}")
    
    
    if __name__ == "__main__":
        typer.run(main)
    

    Description

    It would be convenient to be able to specify help text for arguments and options via the function's docstring in addition to the current method. At the moment, of course, help can only be specified for the command itself via the function's docstring.

    Wanted Solution

    To be able to specify help text for command arguments and options via the function docstring, as below.

    Wanted Code

    This should behave in a totally equivalent way to the above example of code that already works.

    import typer
    
    
    def main(name: str = typer.Argument(...)):
        """
        Say hi to NAME very gently, like Dirk.
    
        :param name: The name of the user to greet
        """
        typer.echo(f"Hello {name}")
    
    
    if __name__ == "__main__":
        typer.run(main)
    

    Note, the other standard syntax for parameter descriptions in functions is @param name: The name of the user to greet, and this should also be supported, I would think.

    Alternatives

    Just use the current method of specifying help text in the function signature, via arg = typer.Argument(..., help="<text>") or opt = typer.Option(..., help="<text>"). I argue that a) this can be seen as "polluting" the function signature and making it harder to read quickly/easily, b) it is most consistent to be able to specify help text for a command and its arguments 100% through docstrings (if so desired).

    Operating System

    macOS

    Operating System Details

    No response

    Typer Version

    0.4.0

    Python Version

    3.9.6

    Additional Context

    No response

    enhancement 
    opened by alexreg 0
  • Try clarify testing documentation about stderr

    Try clarify testing documentation about stderr

    Hello. First thank for all your hard work on this project.

    Today I wanted to test a small utility function and check that a message was printed into the standard error.

    From the documentation, the only mention was

    You could also check result.stderr for "standard error".

    But using it directly, in fact, does not work.

    After looking the code, it seems that Click's CliRunner mix standard output and error on stdout by default. You need to ask explicitly to do not mix them in order to be able to read the result.stderr property.

    Then, I find the current documentation confusing because does not mention that and can lead reader to think it should work out of the box. In fact, I firsts started by double-checking my code before understand that the runner did not have the expected behavior.

    So I suggest a small addition to the current note, at least to provide insight for readers.

    Please let me know if I can improve it.

    opened by cgabard 0
  • typer.Argument with autocompletion

    typer.Argument with autocompletion

    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

    Not working:
        myparam: str = typer.Argument(
            "",
            shell_complete=my_autocomplete,
        )
    
    Working:
        myparam: str = typer.Option(
            "",
            shell_complete=my_autocomplete,
        ),
    

    Description

    I'm trying to enable shell complete on an Argument but it does not work. On the opposite with Options everything is working as expected

    I think that the same problem was already in the previous versions of typer (so that it is NOT introduced by typer 0.4.0 & click 8... but i'm not totally sure about that)

    Based on tests on click, shell_complete on arguments should work: https://github.com/pallets/click/blob/48cb86d85fc1abfcf1478ee660e42aaa5382fd64/examples/completion/completion.py#L25

    in typer I can't find tests with arguments, I only found this with option https://github.com/tiangolo/typer/blob/a1520dcda685220a9a796288f5eaaebd00d68845/tests/assets/compat_click7_8.py#L20

    Operating System

    Linux

    Operating System Details

    Ubuntu 20.04

    Typer Version

    0.4.0

    Python Version

    Python 3.9.5

    Additional Context

    click 8.0.1

    question 
    opened by mdantonio 0
  • Update package.md

    Update package.md

    fix(docs): in tutorial/package, add missing quotation mark to name == "__main__

    opened by ryanstreur 0
  • Added async_command to typer.Typer

    Added async_command to typer.Typer

    From my comment in:

    tiangolo#88

    Allows command to be used with async.

    Let me know if using *args, **kwargs is ok or if it needs to be typed. *args, **kwargs will be more maintainable. Further we could just make @app.command DETECT if it's attached to an async function, but that might be more challenging.

    opened by ryanpeach 3
  • [Feature] positional-only args are always Arguments, keyword-only args are always Options, normal args are unchanged

    [Feature] positional-only args are always Arguments, keyword-only args are always Options, normal args are unchanged

    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 pathlib import Path
    import typer
    
    
    # in this example we want 'workdir' to be Argument and we want 'name' and 'age' to be Option
    def main(workdir: Path = Argument(Path.cwd()), name: str = typer.Option(...), age: int = typer.Option(...))
        ...
    
    
    if __name__ == '__main__':
        typer.run(main)
    

    Description

    • Make it easier to write arguments with default values (uncommonly needed) and options without default values (often needed)
    • Currently the most common cases where none of the extra arguments of typer.Argument or typer.Option are needed aside from the default value are more verbose than they need to be and don't take advantage of python's syntactic sugar for positional-only and keyword-only arguments

    Wanted Solution

    Have typer leave normal arguments the same as they are currently for backwards-compatibility but allow positional-only arguments to always create an Argument instance (even if given a default value), while keyword-only arguments would always result in an Option instance (even without a default value)

    Wanted Code

    from pathlib import Path
    import typer
    
    
    # 'workdir' will be interpreted as an Argument; 'name' and 'int' will each be interpreted as an Option
    def main(workdir: Path = Path.cwd(), /, *, name: str, age: int)
        ...
    
    
    if __name__ == '__main__':
        typer.run(main)
    

    Alternatives

    No response

    Operating System

    Windows

    Operating System Details

    No response

    Typer Version

    0.3.2

    Python Version

    Python 3.9.0rc1

    Additional Context

    No response

    enhancement 
    opened by matthewgdv 0
  • How to use the `flag_value` option properly?

    How to use the `flag_value` option properly?

    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

    import typer
    from typer import Argument, Option
    
    
    def main(
        const_option: str = Option(
            "foo",
            "--const_option",
            is_flag=True,
            flag_value="bar",
        ),
    ):
        print(const_option)
    
    
    if __name__ == "__main__":
        typer.run(main)
    

    Description

    What I expect:

    C:\>script
    foo
    
    C:\>script --const_option
    bar
    

    What happens:

    C:\>script
    bar
    
    C:\>script --const_option
    bar
    

    Not sure what I am doing wrong here, can someone point me to the right direction?

    Operating System

    Windows

    Operating System Details

    No response

    Typer Version

    0.4.0

    Python Version

    Python 3.9.4

    Additional Context

    No response

    question 
    opened by archiif 1
  • Brief implementation for #111

    Brief implementation for #111

    Brief support for #111.

    • the plain Pydantic models are handled the same way as Tuples.
    • more complicated Pydantic models are handles as FileText.

    The implementation definitely can be improved. Please let me know what do you think.

    opened by kdeyev 0
  • Main app with no commands no longer shows callback docstring in v0.4.0

    Main app with no commands no longer shows callback docstring in v0.4.0

    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

    import typer
    
    app = typer.Typer()
    
    @app.callback()
    def main():
        """Main program help text."""
        pass
    
    @app.command()
    def foo():
        """foo command help text."""
        typer.echo("Executed foo.")
    
    if __name__ == "__main__":
        app()
    

    Description

    Not sure if this should be considered a bug or enhancement, since this was an undocumented change that could potentially be considered a regression.

    • In typer<=0.3.2, when the main application is executed without any commands, it would previously print the help text from the callback and exit with status code 0.
    • In typer 0.4.0, this same behavior prints only Try 'app.py --help' for help. and Error: Missing command. and exits with status code 2.

    I'm fine with the status code change—it does seem to me like an improvement that it has an error code. Thank you for this change. (Though it would be nice for this to be documented in the change log.)

    However, I think it would be useful to also directly print the help text without requiring users to make another invocation with --help, as was the previous behavior. The git program, for example, will exit with status 1 but also print the help text when used without any commands.

    This appears to be only a typer change, and not a click change, as typer 0.4.0 behaves the same with way both click 8.0.1 and click 7.1.2.

    typer 0.4.0; click 8.0.1

    ❯ python -c "import typer; print('typer', typer.__version__); import click; print('click', click.__version__)"
    typer 0.4.0
    click 8.0.1
    
    ❯ python app.py
    Usage: app.py [OPTIONS] COMMAND [ARGS]...
    Try 'app.py --help' for help.
    
    Error: Missing command.
    
    ❯ echo $?
    2
    

    typer 0.4.0; click 7.1.2

    ❯ python -c "import typer; print('typer', typer.__version__); import click; print('click', click.__version__)"
    typer 0.4.0
    click 7.1.2
    
     ❯ python app.py
    Usage: app.py [OPTIONS] COMMAND [ARGS]...
    Try 'app.py --help' for help.
    
    Error: Missing command.
    
    ❯ echo $?
    2
    

    typer 0.3.2; click 7.1.2

    ❯ python -c "import typer; print('typer', typer.__version__); import click; print('click', click.__version__)"
    typer 0.3.2
    click 7.1.2
    
    ❯ python app.py
    Usage: app.py [OPTIONS] COMMAND [ARGS]...
    
      Main program help text.
    
    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:
      foo  foo command help text.
    
    ❯ echo $?
    0
    

    Operating System

    macOS

    Operating System Details

    No response

    Typer Version

    0.4.0

    Python Version

    3.8.10

    Additional Context

    No response

    question 
    opened by jayqi 0
  • ✏️  Fix markdown in DateTime doc

    ✏️ Fix markdown in DateTime doc

    Seel DateTime formats list at: https://typer.tiangolo.com/tutorial/parameter-types/datetime/

    opened by kozlek 0
Releases(0.4.0)
Owner
Sebastián Ramírez
Creator of FastAPI and Typer. Dev at @explosion. APIs, Deep Learning/ML, full-stack distributed systems, SQL/NoSQL, Python, Docker, JS, TypeScript, etc
Sebastián Ramírez
A thin, practical wrapper around terminal capabilities in Python

Blessings Coding with Blessings looks like this... from blessings import Terminal t = Terminal() print(t.bold('Hi there!')) print(t.bold_red_on_brig

Erik Rose 1.3k Oct 19, 2021
A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables.

ConfigArgParse Overview Applications with more than a handful of user-settable options are best configured through a combination of command line args,

null 544 Oct 18, 2021
Pythonic command line arguments parser, that will make you smile

docopt creates beautiful command-line interfaces Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python N

null 7.5k Oct 25, 2021
Color text streams with a polished command line interface

colout(1) -- Color Up Arbitrary Command Output Synopsis colout [-h] [-r RESOURCE] colout [-g] [-c] [-l min,max] [-a] [-t] [-T DIR] [-P DIR] [-d COLORM

nojhan 1.1k Sep 28, 2021
sane is a command runner made simple.

sane is a command runner made simple.

Miguel M. 14 Jul 24, 2021
Python and tab completion, better together.

argcomplete - Bash tab completion for argparse Tab complete all the things! Argcomplete provides easy, extensible command line tab completion of argum

Andrey Kislyuk 991 Oct 22, 2021
Cleo allows you to create beautiful and testable command-line interfaces.

Cleo Create beautiful and testable command-line interfaces. Cleo is mostly a higher level wrapper for CliKit, so a lot of the components and utilities

Sébastien Eustace 763 Oct 15, 2021
Simple cross-platform colored terminal text in Python

Colorama Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows. PyPI for releases |

Jonathan Hartley 2.6k Oct 23, 2021
Library for building powerful interactive command line applications in Python

Python Prompt Toolkit prompt_toolkit is a library for building powerful interactive command line applications in Python. Read the documentation on rea

prompt-toolkit 7.3k Oct 23, 2021
Rich is a Python library for rich text and beautiful formatting in the terminal.

Rich 中文 readme • lengua española readme • Läs på svenska Rich is a Python library for rich text and beautiful formatting in the terminal. The Rich API

Will McGugan 30.4k Oct 24, 2021
Command line animations based on the state of the system

shell-emotions Command line animations based on the state of the system for Linux or Windows 10 The ascii animations were created using a modified ver

Simon Malave 61 Oct 21, 2021
Python library that measures the width of unicode strings rendered to a terminal

Introduction This library is mainly for CLI programs that carefully produce output for Terminals, or make pretend to be an emulator. Problem Statement

Jeff Quast 250 Oct 15, 2021
Cement is an advanced Application Framework for Python, with a primary focus on CLI

Cement Framework Cement is an advanced Application Framework for Python, with a primary focus on Command Line Interfaces (CLI). Its goal is to introdu

Data Folk Labs, LLC 1k Oct 25, 2021
CalcuPy 📚 Create console-based calculators in a few lines of code.

CalcuPy ?? Create console-based calculators in a few lines of code. ?? Installation pip install calcupy ?? Usage from calcupy import Calculator calc

Dylan Tintenfich 6 Sep 26, 2021
A cross platform package to do curses-like operations, plus higher level APIs and widgets to create text UIs and ASCII art animations

ASCIIMATICS Asciimatics is a package to help people create full-screen text UIs (from interactive forms to ASCII animations) on any platform. It is li

null 2.8k Oct 23, 2021
emoji terminal output for Python

Emoji Emoji for Python. This project was inspired by kyokomi. Example The entire set of Emoji codes as defined by the unicode consortium is supported

Taehoon Kim 1.3k Oct 16, 2021
plotting in the terminal

bashplotlib plotting in the terminal what is it? bashplotlib is a python package and command line tool for making basic plots in the terminal. It's a

Greg Lamp 1.6k Oct 17, 2021
A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team.

Roid ?? A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team. ?? Installation You can install roid in it's default

Harrison Burt 7 Oct 17, 2021
Python Command-line Application Tools

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 57 Oct 12, 2021