## 1. Project Overview & Quickstart (fastapi/typer)

## File: README.md

---

**Documentation**: [https://typer.tiangolo.com](https://typer.tiangolo.com)

**Source Code**: [https://github.com/fastapi/typer](https://github.com/fastapi/typer)

---

Typer is a library for building <abbr title="command line interface, programs executed from a terminal">CLI</abbr> applications that users will **love using** and developers will **love creating**. Based on Python type hints.

It's also a command line tool to run scripts, automatically converting them to CLI applications.

The key features are:

* **Intuitive to write**: Great editor support. <abbr title="also known as auto-complete, autocompletion, IntelliSense">Completion</abbr> 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.
* **Run scripts**: Typer includes a `typer` command/program that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.

## FastAPI of CLIs

**Typer** is [FastAPI](https://fastapi.tiangolo.com)'s little sibling, it's the FastAPI of CLIs.

## Installation

First, [install `uv`](https://docs.astral.sh/uv/getting-started/installation/), and then add **Typer** to your project:



```console
$ uv add typer
---> 100%
```



This installs both the Typer library and the `typer` command in the project's virtual environment. To use `typer` directly with shell completion, [activate the project environment and install completion](tutorial/install.md#activate-the-virtual-environment).

If you prefer to use `pip`, install `typer` inside a virtual environment. See the [installation guide](tutorial/install.md) for the alternative steps.

## Example

### The absolute minimum

* Create a file `main.py` with:

```Python
def main(name: str):
    print(f"Hello {name}")
```

This script doesn't even use Typer internally. But you can use the `typer` command to run it as a CLI application.

### Run it

Run your application with the `typer` command:



```console
// Run your application
$ typer main.py run

// You get a nice error, you are missing 'name'
Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name}
Try 'typer [PATH_OR_MODULE] run --help' for help.
╭─ Error ───────────────────────────────────────────╮
│ Missing argument 'name'.                          │
╰───────────────────────────────────────────────────╯


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

Usage: typer [PATH_OR_MODULE] run [OPTIONS] {name}

Run the provided Typer app.

╭─ Arguments ───────────────────────────────────────╮
│ *    name      <str>  [required]                  │
╰───────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────╮
│ --help          Show this message and exit.       │
╰───────────────────────────────────────────────────╯

// Now pass the 'name' argument
$ typer main.py run Camila

Hello Camila

// It works! 🎉
```



This is the simplest use case, not even using Typer internally, but it can already be quite useful for simple scripts.

**Note**: auto-completion works when you create a Python package and run it with `--install-completion` or when you use the `typer` command.

## Use Typer in your code

Now let's start using Typer in your own code, update `main.py` with:

```Python
import typer


def main(name: str):
    print(f"Hello {name}")


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

Now you could run it with Python directly:



```console
// Run your application
$ uv run 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
$ uv run python main.py --help

Usage: main.py [OPTIONS] {name}

╭─ Arguments ───────────────────────────────────────╮
│ *    name      <str>  [required]                  │
╰───────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────╮
│ --help          Show this message and exit.       │
╰───────────────────────────────────────────────────╯

// Now pass the 'name' argument
$ uv run python main.py Camila

Hello Camila

// It works! 🎉
```



**Note**: you can also call this same script with the `typer` command, but you don't need to.

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

```Python hl_lines="3  6  11  20"
import typer

app = typer.Typer()


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


@app.command()
def goodbye(name: str, formal: bool = False):
    if formal:
        print(f"Goodbye Ms. {name}. Have a good day.")
    else:
        print(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 new help:



```console
$ uv run 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 ────────────────────────────────────────╮
│ hello                                             │
│ goodbye                                           │
╰───────────────────────────────────────────────────╯

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

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



Now check the help for the `hello` command:



```console
$ uv run python main.py hello --help

 Usage: main.py hello [OPTIONS] {name}

╭─ Arguments ───────────────────────────────────────╮
│ *    name      <str>  [required]                  │
╰───────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────╮
│ --help          Show this message and exit.       │
╰───────────────────────────────────────────────────╯
```



And now check the help for the `goodbye` command:



```console
$ uv run python main.py goodbye --help

 Usage: main.py goodbye [OPTIONS] {name}

╭─ Arguments ───────────────────────────────────────╮
│ *    name      <str>  [required]                  │
╰───────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────╮
│ --formal    --no-formal      [default: no-formal] │
│ --help                       Show this message    │
│                              and exit.            │
╰───────────────────────────────────────────────────╯

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



Now you can try out the new command line application:



```console
// Use it with the hello command

$ uv run python main.py hello Camila

Hello Camila

// And with the goodbye command

$ uv run python main.py goodbye Camila

Bye Camila!

// And with --formal

$ uv run python main.py goodbye --formal Camila

Goodbye Ms. Camila. Have a good day.
```



**Note**: If your app only has one command, by default the command name is **omitted** in usage: `python main.py Camila`. However, when there are multiple commands, you must **explicitly include the command name**: `python main.py hello Camila`. See [One or Multiple Commands](https://typer.tiangolo.com/tutorial/commands/one-or-multiple/) for more details.

### 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**.

For example, for an `int`:

```Python
total: int
```

or for a `bool` flag:

```Python
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 the `typer` command.

For a more complete example including more features, see the [Tutorial - User Guide](https://typer.tiangolo.com/tutorial/).

## Dependencies

**Typer** requires only a few dependencies (most are tiny):

* [`rich`](https://rich.readthedocs.io/en/stable/index.html): to show nicely formatted errors automatically.
* [`shellingham`](https://github.com/sarugaku/shellingham): to automatically detect the current shell when installing completion.
* [`annotated-doc`](https://github.com/fastapi/annotated-doc): to generate documentation from Python type annotations.
* [`colorama`](https://github.com/tartley/colorama) (only on Windows): for producing colored terminal text on Windows.

### Click code

Typer used to depend on [Click](https://click.palletsprojects.com/) as well, a popular tool for building CLIs in Python.

Since version 0.26.0, Typer has vendored Click (included Click's source code internally, instead of installing it as a third party package) and has unified the code interactions between Typer and the embedded Click source code for easier maintainability in the future.

Note that some Click functionality will not be available anymore in the future, as we continue to improve and extend Typer's codebase.

### `typer-slim`

There used to be a slimmed-down version of Typer called `typer-slim`, which didn't include the dependencies `rich` and `shellingham`, nor the `typer` command.

However, since version 0.22.0, we have stopped supporting this, and `typer-slim` now simply installs (all of) Typer.

If you want to disable Rich globally, you can set an environmental variable `TYPER_USE_RICH` to `False` or `0`.

## License

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

---

## File: docs/resources/index.md

# Resources

Additional resources, how to **help** and get help, how to **contribute**, and more. ✈️

---

## File: docs/tutorial/arguments/default.md

# CLI Arguments with Default

We can also use the same `typer.Argument()` to set a default value.

That way the *CLI argument* will be optional *and also* have a default value.

## An optional *CLI argument* with a default

We can also use `typer.Argument()` to make a *CLI argument* have a default value other than `None`:

{* docs_src/arguments/default/tutorial001_an_py310.py hl[9] *}

/// tip

Because now the value will be a `str` passed by the user or the default value of `"Wade Wilson"` which is also a `str`, we know the value will never be `None`, so we don't have to (and shouldn't) use `Optional[str]`.

Have in mind that the `Optional[something]` tells Python that a value "could be `None`". But the use of `Optional` doesn't affect Typer in any way, e.g. it doesn't tell Typer if a value is required or not.

///

Check it:



```console
// Check the help
$ uv run python main.py --help

// Notice the [default: Wade Wilson] ✨
Usage: main.py [OPTIONS] [name]

Arguments:
  name  [default: Wade Wilson]

Options:
  --help                Show this message and exit.

// With no optional CLI argument
$ uv run python main.py

Hello Wade Wilson

// With one CLI argument
$ uv run python main.py Camila

Hello Camila
```



## Dynamic default value

And we can even make the default value be dynamically generated by passing a function as the `default_factory` argument:

{* docs_src/arguments/default/tutorial002_an_py310.py hl[9:10,14] *}

In this case, we created the function `get_name` that will just return a random `str` each time.

And we pass it as the first function argument to `typer.Argument()`.

/// tip

The word "factory" in `default_factory` is just a fancy way of saying "function that will create the default value".

///

Check it:



```console
// Check the help
$ uv run python main.py --help

Usage: main.py [OPTIONS] [name]

Arguments:
  name  [default: (dynamic)]

Options:
  --help                Show this message and exit.

// Try it several times, it will use a random default each time
$ uv run python main.py

Hello Deadpool

$ uv run python main.py

Hello Hiro

$ uv run python main.py

Hello Rick

// Now pass a value for the CLI argument
$ uv run python main.py Camila

Hello Camila
```

---

## File: docs/tutorial/arguments/envvar.md

# CLI Arguments with Environment Variables

You can also configure a *CLI argument* to read a value from an environment variable if it is not provided in the command line as a *CLI argument*.

An **environment variable** (also known as an **env var**) is a value that lives outside of your Python code, in the operating system, and can be read by your application and other programs.

/// tip

Read the [Environment Variables guide](https://tiangolo.com/guides/environment-variables/) for a detailed, cross-platform explanation.

///

To do that, use the `envvar` parameter for `typer.Argument()`:

{* docs_src/arguments/envvar/tutorial001_an_py310.py hl[9] *}

In this case, the *CLI argument* `name` will have a default value of `"World"`, but will also read any value passed to the environment variable `AWESOME_NAME` if no value is provided in the command line:



```console
// Check the help
$ uv run python main.py --help

Usage: main.py [OPTIONS] [name]

Arguments:
  name  [env var: AWESOME_NAME; default: World]

Options:
  --help                Show this message and exit.

// Call it without a CLI argument
$ uv run python main.py

Hello Mr. World

// Now pass a value for the CLI argument
$ uv run python main.py Czernobog

Hello Mr. Czernobog

// And now use the environment variable
$ AWESOME_NAME=Wednesday uv run python main.py

Hello Mr. Wednesday

// CLI arguments take precedence over env vars
$ AWESOME_NAME=Wednesday uv run python main.py Czernobog

Hello Mr. Czernobog
```



/// tip | Windows PowerShell

In PowerShell, set the environment variable first and then run the command:

```console
$ $Env:AWESOME_NAME = "Wednesday"
$ uv run python main.py
```

///

## Multiple environment variables

You are not restricted to a single environment variable, you can declare a list of environment variables that could be used to get a value if it was not passed in the command line:

{* docs_src/arguments/envvar/tutorial002_an_py310.py hl[10] *}

Check it:



```console
// Check the help
$ uv run python main.py --help

Usage: main.py [OPTIONS] [name]

Arguments:
  name  [env var: AWESOME_NAME, GOD_NAME; default: World]

Options:
  --help                Show this message and exit.

// Try the first env var
$ AWESOME_NAME=Wednesday uv run python main.py

Hello Mr. Wednesday

// Try the second env var
$ GOD_NAME=Anubis uv run python main.py

Hello Mr. Anubis
```



## Hide an env var from the help text

By default, environment variables used will be shown in the help text, but you can disable them with `show_envvar=False`:

{* docs_src/arguments/envvar/tutorial003_an_py310.py hl[11] *}

Check it:



```console
//Check the help
$ uv run python main.py --help

// It won't show the env var
Usage: main.py [OPTIONS] [name]

Arguments:
  name  [default: World]

Options:
  --help                Show this message and exit.

// But it will still be able to use it
$ AWESOME_NAME=Wednesday uv run python main.py

Hello Mr. Wednesday
```

---

## File: docs/tutorial/arguments/help.md

# CLI Arguments with Help

In the *First Steps* section you saw how to add help for a CLI app/command by adding it to a function's <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr>.

Here's how that last example looked like:

{* docs_src/first_steps/tutorial006_py310.py *}

Now that you also know how to use `typer.Argument()`, let's use it to add documentation specific for a *CLI argument*.

## Add a `help` text for a *CLI argument*

You can use the `help` parameter to add a help text for a *CLI argument*:

{* docs_src/arguments/help/tutorial001_an_py310.py hl[9] *}

And it will be used in the automatic `--help` option:



```console
$ uv run python main.py --help

// Check the section with Arguments below 🚀
Usage: main.py [OPTIONS] {name}

Arguments:
  name  The name of the user to greet  [required]

Options:
  --help                Show this message and exit.
```



## Combine help text and docstrings

And of course, you can also combine that `help` with the <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr>:

{* docs_src/arguments/help/tutorial002_an_py310.py hl[9:12] *}

And the `--help` option will combine all the information:



```console
$ uv run python main.py --help

// Notice that we have the help text from the docstring and also the Arguments 📝
Usage: main.py [OPTIONS] {name}

  Say hi to 'name' very gently, like Dirk.

Arguments:
  name  The name of the user to greet  [required]

Options:
  --help                Show this message and exit.
```



## Help with defaults

If you have a *CLI argument* with a default value, like `"World"`:

{* docs_src/arguments/help/tutorial003_an_py310.py hl[9] *}

It will show that default value in the help text:



```console
$ uv run python main.py --help

// Notice the [default: World] 🔍
Usage: main.py [OPTIONS] [name]

  Say hi to 'name' very gently, like Dirk.

Arguments:
  name  Who to greet  [default: World]

Options:
  --help                Show this message and exit.
```



But you can disable that if you want to, with `show_default=False`:

{* docs_src/arguments/help/tutorial004_an_py310.py hl[11] *}

And then it won't show the default value:



```console
$ uv run python main.py --help

// Notice the there's no [default: World] now 🔥
Usage: main.py [OPTIONS] [name]

  Say hi to 'name' very gently, like Dirk.

Arguments:
  name  Who to greet

Options:
  --help                Show this message and exit.
```



## Custom default string

You can use the same `show_default` to pass a custom string (instead of a `bool`) to customize the default value to be shown in the help text:

{* docs_src/arguments/help/tutorial005_an_py310.py hl[13] *}

And it will be used in the help text:



```console
$ uv run python main.py --help

Usage: main.py [OPTIONS] [name]

Arguments:
  name  Who to greet  [default: (Deadpoolio the amazing's name)]


Options:
  --help                Show this message and exit.

// See it shows "(Deadpoolio the amazing's name)" instead of the actual default of "Wade Wilson"
```



## Custom help name (`metavar`)

You can also customize the text used in the generated help text to represent a *CLI argument*.

By default, it will be the same name you declared, with casing preserved.

So, if you declare it as:

```Python
name: str
```

It will be shown as:

```
name
```

But you can customize it with the `metavar` parameter for `typer.Argument()`.

For example, let's say you don't want to have the default of `name`, you want to have `username`, and you really want ✨ emojis ✨ everywhere:

{* docs_src/arguments/help/tutorial006_an_py310.py hl[9] *}

Now the generated help text will have `✨username✨` instead of `name`:



```console
$ uv run python main.py --help

Usage: main.py [OPTIONS] [✨username✨]

Arguments:
  ✨username✨  [default: World]

Options:
  --help                Show this message and exit.
```



## *CLI Argument* help panels

You might want to show the help information for *CLI arguments* in different panels when using the `--help` option.

If you have installed Rich as described in the docs for [Printing and Colors](../printing.md), you can set the `rich_help_panel` parameter to the name of the panel where you want this *CLI argument* to be shown:

{* docs_src/arguments/help/tutorial007_an_py310.py hl[12,16] *}

Then, if you check the `--help` option, you will see a default panel named "`Arguments`" for the *CLI arguments* that don't have a custom `rich_help_panel`.

And next you will see other panels for the *CLI arguments* that have a custom panel set in the `rich_help_panel` parameter:



```console
$ uv run python main.py --help

** ****Usage: ****main.py [OPTIONS] {name} [lastname] [age]               **
**                                                                     **
 Say hi to 'name' very gently, like Dirk.

╭─ Arguments ───────────────────────────────────────────────────────╮
│ *    name      **str**  Who to greet [default: None] [required]       │
╰───────────────────────────────────────────────────────────────────╯
╭─ Secondary Arguments ─────────────────────────────────────────────╮
│   lastname      **lastname**  The last name                           │
│   age           **age     **  The user&apos;s age                          │
╰───────────────────────────────────────────────────────────────────╯
╭─ Options ─────────────────────────────────────────────────────────╮
│ **--help**                        Show this message and exit.         │
╰───────────────────────────────────────────────────────────────────╯
```



In this example we have a custom *CLI arguments* panel named "`Secondary Arguments`".

## Help with style using Rich

In a future section you will see how to use custom markup in the `help` for *CLI arguments* when reading about [Commands - Command Help](../commands/help.md#rich-markdown-and-markup).

If you are in a hurry you can jump there, but otherwise, it would be better to continue reading here and following the tutorial in order.

## Hide a *CLI argument* from the help text

If you want, you can make a *CLI argument* **not** show up in the `Arguments` section in the help text.

You will probably not want to do this normally, but it's possible:

{* docs_src/arguments/help/tutorial008_an_py310.py hl[9] *}

Check it:



```console
$ uv run python main.py --help

// Notice there's no Arguments section at all 🔥
Usage: main.py [OPTIONS] [name]

  Say hi to 'name' very gently, like Dirk.

Options:
  --help                Show this message and exit.
```



/// note

Have in mind that the *CLI argument* will still show up in the first line with `Usage`.

But it won't show up in the main help text under the `Arguments` section.

///

### Help text for *CLI arguments*

**Typer supports `help` for *CLI arguments*** to make it easier to have consistent help texts with a consistent format for your CLI programs. 🎨

This is also to help you create CLI programs that are ✨ awesome ✨ *by default*. With very little code.

If you don't want the CLI Argument to be shown in help outputs, you can set the `hidden` parameter to `True`.

---

## File: docs/tutorial/arguments/index.md

# CLI Arguments

In the next few sections we'll see some ways to modify how *CLI arguments* work.

We'll create optional *CLI arguments*, we'll add integrated help for *CLI arguments*, etc.

---

## File: docs/tutorial/arguments/optional.md

# Optional CLI Arguments

We said before that *by default*:

* *CLI options* are **optional**
* *CLI arguments* are **required**

Again, that's how they work *by default*, and that's the convention in many CLI programs and systems.

But you can change that.

In fact, it's very common to have **optional** *CLI arguments*, it's way more common than having **required** *CLI options*.

As an example of how it could be useful, let's see how the `ls` CLI program works.



```console
// If you just type
$ ls

// ls will "list" the files and directories in the current directory
typer  tests  README.md  LICENSE

// But it also receives an optional CLI argument
$ ls ./tests/

// And then ls will list the files and directories inside of that directory from the CLI argument
__init__.py  test_tutorial
```



## An alternative *CLI argument* declaration

In the [First Steps](../first-steps.md#add-a-cli-argument) you saw how to add a *CLI argument*:

{* docs_src/first_steps/tutorial002_py310.py hl[4] *}

Now let's see an alternative way to create the same *CLI argument*:

{* docs_src/arguments/optional/tutorial000_an_py310.py hl[6] *}

Or, using an explicit `Typer()` instance creation:

{* docs_src/arguments/optional/tutorial001_an_py310.py hl[9] *}

/// note

Typer added support for `Annotated` (and started recommending it) in version 0.9.0.

If you have an older version, you would get errors when trying to use `Annotated`.

Make sure you upgrade the Typer version to at least 0.9.0 before using `Annotated`.

///

Before, you had this function parameter:

```Python
name: str
```

And now we wrap it with `Annotated`:

```Python
name: Annotated[str]
```

Both of these versions mean the same thing, `Annotated` is part of standard Python and is there for this.

But the second version using `Annotated` allows us to pass additional metadata that can be used by **Typer**:

```Python
name: Annotated[str, typer.Argument()]
```

Now we are being explicit that `name` is a *CLI argument*. It's still a `str` and it's still required (it doesn't have a default value).

All we did there achieves the same thing as before, a **required** *CLI argument*:



```console
$ uv run python main.py

Usage: main.py [OPTIONS] {name}
Try "main.py --help" for help.

Error: Missing argument 'name'.
```



It's still not very useful, but it works correctly.

And being able to declare a **required** *CLI argument* using

```Python
name: Annotated[str, typer.Argument()]
```

...that works exactly the same as

```Python
name: str
```

...will come handy later.

## Make an optional *CLI argument*

Now, finally what we came for, an optional *CLI argument*.

To make a *CLI argument* optional, use `typer.Argument()` and make sure to provide a "default" value, for example `"World"`:

{* docs_src/arguments/optional/tutorial002_an_py310.py hl[9] *}

Now we have:

```Python
name: Annotated[str, typer.Argument()] = "World"
```

Because we are using `typer.Argument()` **Typer** will know that this is a *CLI argument* (no matter if *required* or *optional*).

Check the help:



```console
// First check the help
$ uv run python main.py --help

Usage: main.py [OPTIONS] [name]

Arguments:
  name  [default: World]

Options:
  --help                Show this message and exit.
```



/// tip

Notice that `name` is still a *CLI argument*, it's shown up there in the "`Usage: main.py` ...".

Also notice that now `[name]` has rectangular brackets ("`[`" and "`]`") around it to denote that it's **optional**, not **required**. If it would have been required, curly brackets ("`{`" and "`}`") would be used instead.

///

Now run it and test it:



```console
// With no CLI argument
$ uv run python main.py

Hello World!

// With one optional CLI argument
$ uv run python main.py Camila

Hello Camila
```



/// tip

Notice that "`Camila`" here is an optional *CLI argument*, not a *CLI option*, because we didn't use something like "`--name Camila`", we just passed "`Camila`" directly to the program.

///

## Alternative (old) `typer.Argument()` as the default value

**Typer** also supports another older alternative syntax for declaring *CLI arguments* with additional metadata.

Instead of using `Annotated`, you can use `typer.Argument()` as the default value:

{* docs_src/arguments/optional/tutorial001_py310.py hl[7] *}

/// tip

Prefer to use the `Annotated` version if possible.

///

Before, because `name` didn't have any default value it would be a **required parameter** for the Python function, in Python terms.

When using `typer.Argument()` as the default value **Typer** does the same and makes it a **required** *CLI argument*.

We changed it to:

```Python
name: str = typer.Argument()
```

But now as `typer.Argument()` is the "default value" of the function's parameter, it would mean that "it is no longer required" (in Python terms).

As we no longer have the Python function default value (or its absence) to tell if something is required or not and what is the default value, `typer.Argument()` receives a first parameter `default` that serves the same purpose of defining that default value, or making it required.

Not passing any value to the `default` argument is the same as marking it as required. But you can also explicitly mark it as *required* by passing `...` as the `default` argument, passed to `typer.Argument(default=...)`.

```Python
name: str = typer.Argument(default=...)
```

/// note

If you hadn't seen that `...` before: it is a special single value, it is [part of Python and is called "Ellipsis"](https://docs.python.org/3/library/constants.html#Ellipsis).

///

{* docs_src/arguments/optional/tutorial003_py310.py hl[7] *}

And the same way, you can make it optional by passing a different `default` value, for example `"World"`:

{* docs_src/arguments/optional/tutorial002_py310.py hl[7] *}

Because the first parameter passed to `typer.Argument(default="World")` (the new "default" value) is `"World"`, **Typer** knows that this is an **optional** *CLI argument*, if no value is provided when calling it in the command line, it will have that default value of `"World"`.

The `default` argument is the first one, so it's possible that you see code that passes the value without explicitly using `default=`, like:

```Python
name: str = typer.Argument(...)
```

...or like:

```Python
name: str = typer.Argument("World")
```

...but again, try to use `Annotated` if possible, that way your code in terms of Python will mean the same thing as with **Typer** and you won't have to remember any of these details.

---

## File: docs/tutorial/arguments/other-uses.md

# Other uses

`typer.Argument()` has several other use cases. Such as for data validation, to enable other features, etc.

You will see about these use cases later in the docs.

---

## File: docs/tutorial/commands/arguments.md

# Command CLI Arguments

The same way as with a CLI application with a single command, subcommands (or just "commands") can also have their own *CLI arguments*:

{* docs_src/commands/arguments/tutorial001_py310.py hl[7,12] *}



```console
// Check the help for create
$ uv run python main.py create --help

Usage: main.py create [OPTIONS] {username}

Arguments:
  username  [required]

Options:
  --help  Show this message and exit.

// Call it with a CLI argument
$ uv run python main.py create Camila

Creating user: Camila

// The same for delete
$ uv run python main.py delete Camila

Deleting user: Camila
```



/// tip

Everything to the *right* of the *command* are *CLI parameters* (*CLI arguments* and *CLI options*) for that command.

///

/// note | Technical Details

Actually, it's everything to the right of that command, *before any subcommand*.

It's possible to have groups of *subcommands*, it's like if one *command* also had *subcommands*. And then those *subcommands* could have their own *CLI parameters*, taking their own *CLI parameters*.

You will see about them later in another section.

///

## 2. Official Technical Reference & Guides (fastapi/annotated-doc)

# Annotated Doc

Document parameters, class attributes, return types, and variables inline, with `Annotated`.

<a href="https://github.com/fastapi/annotated-doc/actions?query=workflow%3ATest+event%3Apush+branch%3Amain" target="_blank">
    
</a>
<a href="https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/annotated-doc" target="_blank">
    
</a>
<a href="https://pypi.org/project/annotated-doc" target="_blank">
    
</a>
<a href="https://pypi.org/project/annotated-doc" target="_blank">
    
</a>

## Installation

```bash
pip install annotated-doc
```

Or with `uv`:

```Python
uv add annotated-doc
```

## Usage

Import `Doc` and pass a single literal string with the documentation for the specific parameter, class attribute, return type, or variable.

For example, to document a parameter `name` in a function `hi` you could do:

```Python
from typing import Annotated

from annotated_doc import Doc

def hi(name: Annotated[str, Doc("Who to say hi to")]) -> None:
    print(f"Hi, {name}!")
```

You can also use it to document class attributes:

```Python
from typing import Annotated

from annotated_doc import Doc

class User:
    name: Annotated[str, Doc("The user's name")]
    age: Annotated[int, Doc("The user's age")]
```

The same way, you could document return types and variables, or anything that could have a type annotation with `Annotated`.

## Who Uses This

`annotated-doc` was made for:

* [FastAPI](https://fastapi.tiangolo.com/)
* [Typer](https://typer.tiangolo.com/)
* [SQLModel](https://sqlmodel.tiangolo.com/)
* [Asyncer](https://asyncer.tiangolo.com/)

`annotated-doc` is supported by [griffe-typingdoc](https://github.com/mkdocstrings/griffe-typingdoc), which powers reference documentation like the one in the [FastAPI Reference](https://fastapi.tiangolo.com/reference/).

## Reasons not to use `annotated-doc`

You are already comfortable with one of the existing docstring formats, like:

* Sphinx
* numpydoc
* Google
* Keras

Your team is already comfortable using them.

You prefer having the documentation about parameters all together in a docstring, separated from the code defining them.

You care about a specific set of users, using one specific editor, and that editor already has support for the specific docstring format you use.

## Reasons to use `annotated-doc`

* No micro-syntax to learn for newcomers, it’s **just Python** syntax.
* **Editing** would be already fully supported by default by any editor (current or future) supporting Python syntax, including syntax errors, syntax highlighting, etc.
* **Rendering** would be relatively straightforward to implement by static tools (tools that don't need runtime execution), as the information can be extracted from the AST they normally already create.
* **Deduplication of information**: the name of a parameter would be defined in a single place, not duplicated inside of a docstring.
* **Elimination** of the possibility of having **inconsistencies** when removing a parameter or class variable and **forgetting to remove** its documentation.
* **Minimization** of the probability of adding a new parameter or class variable and **forgetting to add its documentation**.
* **Elimination** of the possibility of having **inconsistencies** between the **name** of a parameter in the **signature** and the name in the docstring when it is renamed.
* **Access** to the documentation string for each symbol at **runtime**, including existing (older) Python versions.
* A more formalized way to document other symbols, like type aliases, that could use Annotated.
* **Support** for apps using FastAPI, Typer and others.
* **AI Accessibility**: AI tools will have an easier way understanding each parameter as the distance from documentation to parameter is much closer.

## History

I ([@tiangolo](https://github.com/tiangolo)) originally wanted for this to be part of the Python standard library (in [PEP 727](https://peps.python.org/pep-0727/)), but the proposal was withdrawn as there was a fair amount of negative feedback and opposition.

The conclusion was that this was better done as an external effort, in a third-party library.

So, here it is, with a simpler approach, as a third-party library, in a way that can be used by others, starting with FastAPI and friends.

## License

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