You can try this library: https://github.com/greendwin/typer_di

It allows you to use fastapi-style dependencies to share options between commands:

from typing import Annotated
from typer import Option
from typer_di import TyperDI, Depends

app = TyperDI()

def get_config(config_path: Annotated[Path, Option("--config")]) -> Config:
    ...

@app.command()
def first(..., config: Config = Depends(get_config)):
    ...

@app.command()
def second(..., config: Config = Depends(get_config)):
    ...
Answer from Евгений Цымбалюк on Stack Overflow
🌐
Typer
typer.tiangolo.com › tutorial › multiple-values › multiple-options
Multiple CLI Options - Typer
You can declare a CLI option that can be used multiple times, and then get all the values. For example, let's say you want to accept several users in a single execution. For this, use the standard Python list to declare it as a list of str: ... from typing import Annotated import typer app ...
🌐
Jacob Kaplan-Moss
jacobian.org › til › common-arguments-with-typer
Common Arguments With Typer - Jacob Kaplan-Moss
Callbacks are what Typer uses to implement groups or common options. @cli.callback() lets me declare the pinboard_token as a common option, and I can do any error checking (here, just making sure it exists) in the callback. Typer’s documentation suggests saving state (i.e.
🌐
GitHub
github.com › fastapi › typer › issues › 405
Need feature to share options or arguments between commands · Issue #405 · fastapi/typer
June 15, 2022 - I already checked if it is not related to Typer but to Click. ... from typing import Optional, List import typer import os app = typer.Typer() @app.command() def start( debug: bool = typer.Option(False), output_dir: str = typer.Option(os.getcwd()), flows: Optional[List[str]] = typer.Option(None, "--flow", "-f")): typer.echo(f"Debug mode: {debug}") typer.echo(f"Output Dir: {output_dir}") typer.echo(f"start flows: {flows}") @app.command() def stop( debug: bool = typer.Option(False), output_dir: str = typer.Option(os.getcwd())): typer.echo(f"Debug mode: {debug}") typer.echo(f"Output Dir: {output_dir}") typer.echo("STOP!") @app.command() def clean( debug: bool = typer.Option(False), output_dir: str = typer.Option(os.getcwd())): typer.echo(f"Debug mode: {debug}") typer.echo(f"Output Dir: {output_dir}") typer.echo("STOP!") if __name__ == "__main__": app()
Author: fastapi
🌐
Calmcode
calmcode.io › course › typer › options
Calmcode - typer: Options
import typer from typing import List from pathlib import Path app = typer.Typer(name="demo", add_completion=False, help="This is a demo app.") @app.command() def talk(text: str = typer.Argument(..., help="The text to type."), repeat: int = typer.Option(1, help="Number of times to repeat."), loud: bool = typer.Option(False, is_flag=True)): """Talks some text below""" if loud: text = text.upper() for _ in range(repeat): print(text) if __name__ == "__main__": app() The talk command can be run in multiple ways now. python cli.py talk "hello there" python cli.py talk "hello there" --repeat 2 python cli.py talk "hello there" --loud python cli.py talk "hello there" --loud --repeat 3
🌐
Typer
typer.tiangolo.com › tutorial › commands
Commands - Typer
We have seen how to create a CLI program with possibly several CLI options and CLI arguments. But Typer allows you to create CLI programs with several commands (also known as subcommands).
🌐
Typer
typer.tiangolo.com › tutorial › subcommands › nested-subcommands
Nested SubCommands - Typer
import typer import reigns import towns app = typer.Typer() app.add_typer(reigns.app, name="reigns") app.add_typer(towns.app, name="towns") if __name__ == "__main__": app() And now we have a single CLI program with a command (or command group) reigns that has its own commands. And another command towns with its own subcommands. ... // Check the help $ uv run python lands.py --help Usage: lands.py [OPTIONS] COMMAND [ARGS]... Options: --install-completion Install completion for the current shell.
Find elsewhere
🌐
Typer
typer.tiangolo.com › tutorial › options › help
CLI Options with Help - Typer
import typer app = typer.Typer() @app.command() def main(fullname: str = typer.Option("Wade Wilson", show_default=False)): print(f"Hello {fullname}") if __name__ == "__main__": app() And it will no longer show the default value in the help text: $ uv run python main.py Hello Wade Wilson // Show the help $ uv run python main.py --help Usage: main.py [OPTIONS] Options: --fullname <str> --help Show this message and exit.
🌐
Typer
typer.tiangolo.com › tutorial › options › callback-and-context
CLI Option Callback and Context - Typer
In some occasions you might want to have some custom logic for a specific CLI parameter (for a CLI option or CLI argument) that is executed with the value received from the terminal. In those cases you can use a CLI parameter callback function. For example, you could do some validation before the rest of the code is executed. ... from typing import Annotated import typer app = typer.Typer() def name_callback(value: str): if value != "Camila": raise typer.BadParameter("Only Camila is allowed") return value @app.command() def main(name: Annotated[str | None, typer.Option(callback=name_callback)] = None): print(f"Hello {name}") if __name__ == "__main__": app()
🌐
Typer
typer.tiangolo.com › tutorial › commands › one-or-multiple
One or Multiple Commands - Typer
// With the 'name' CLI argument $ uv run python main.py Camila Hello Camila // Asking for help $ uv run python main.py --help Usage: main.py [OPTIONS] {name} 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. ... Notice that it doesn't show a command main, even though the function name is main. But if you add multiple commands, Typer will create one CLI command for each one of them:
🌐
Typer
typer.tiangolo.com › reference › parameters
Parameters - Typer - Tiangolo.com
See [the tutorial about callbacks](https://typer.tiangolo.com/tutorial/options/callback-and-context/) for more details. **Example** ```python def name_callback(value: str): if value != "Deadpool": raise typer.BadParameter("Only Deadpool is allowed") return value @app.command() def main(name: Annotated[str, typer.Argument(callback=name_callback)]): print(f"Hello {name}") ``` """ ), ] = None, metavar: Annotated[ str | None, Doc( """ Customize the name displayed in the help text to represent this CLI Argument.
🌐
Typer
typer.tiangolo.com › tutorial › multiple-values › options-with-multiple-values
CLI Options with Multiple Values - Typer
Python 3.10+ - non-Annotated · Tip · Prefer to use the Annotated version if possible. import typer app = typer.Typer() @app.command() def main(user: tuple[str, int, bool] = typer.Option((None, None, None))): username, coins, is_wizard = user if not username: print("No user provided") raise typer.Abort() print(f"The username {username} has {coins} coins") if is_wizard: print("And this user is a wizard!") if __name__ == "__main__": app() Each of the internal types defines the type of each value in the tuple.
🌐
Typer
typer.tiangolo.com › tutorial › typer-command
typer command - Typer
Instead of using python directly you use the typer command. After the name of the file, add the subcommand run. ✔️ If you installed completion for the typer command as described above, when you hit TAB you will have ✨ completion for everything ✨, including all the subcommands and options of your script, like hello, bye, and --name 🚀.
🌐
Typer
typer.tiangolo.com › tutorial › commands › options
Command CLI Options - Typer
In fact, each command can have different CLI arguments and CLI options: Python 3.10+ from typing import Annotated import typer app = typer.Typer() @app.command() def create(username: str): print(f"Creating user: {username}") @app.command() def delete( username: str, force: Annotated[ bool, typer.Option(prompt="Are you sure you want to delete the user?") ], ): if force: print(f"Deleting user: {username}") else: print("Operation cancelled") @app.command() def delete_all( force: Annotated[ bool, typer.Option(prompt="Are you sure you want to delete ALL users?") ], ): if force: print("Deleting all users") else: print("Operation cancelled") @app.command() def init(): print("Initializing user database") if __name__ == "__main__": app() 🤓 Other versions and variants ·
🌐
Typer
typer.tiangolo.com › tutorial › commands › context
Using the Context - Typer
$ uv run python main.py // The callback is executed Initializing database // Check it with a subcommand $ uv run python main.py create Camila // This time the callback is not executed Creating user: Camila · You can pass configurations for the context when creating a command or callback. For example, you could keep additional CLI parameters not declared in your CLI program with ignore_unknown_options and allow_extra_args. Then you can access those extra raw CLI parameters as a list of str in ctx.args: ... import typer app = typer.Typer() @app.command( context_settings={"allow_extra_args": True, "ignore_unknown_options": True} ) def main(ctx: typer.Context): for extra_arg in ctx.args: print(f"Got extra arg: {extra_arg}") if __name__ == "__main__": app()
🌐
Typer
typer.tiangolo.com › tutorial › parameter-types
CLI Parameter Types - Typer
You can use several data types for the CLI options and CLI arguments, and you can add data validation requirements too. When you declare a CLI parameter with some type Typer will convert the data received in the command line to that data type. For example: Python 3.10+ import typer app = typer.Typer() @app.command() def main(name: str, age: int = 20, height_meters: float = 1.89, female: bool = True): print(f"NAME is {name}, of type: {type(name)}") print(f"--age is {age}, of type: {type(age)}") print(f"--height-meters is {height_meters}, of type: {type(height_meters)}") print(f"--female is {female}, of type: {type(female)}") if __name__ == "__main__": app() In this example, the value received for the CLI argument name will be treated as str.
🌐
Typer
typer.tiangolo.com › tutorial › multiple-values › arguments-with-multiple-values
CLI Arguments with Multiple Values - Typer
Select 3 characters to play with [default: Harry, Hermione, Ron] Options: --help Show this message and exit. // Use it with its defaults $ uv run python main.py Hello Harry Hello Hermione Hello Ron // If you pass an invalid number of arguments you will get an error $ uv run python main.py Draco Hagrid Error: Argument 'names' takes 3 values // And if you pass the exact number of values it will work correctly $ uv run python main.py Draco Hagrid Dobby Hello Draco Hello Hagrid Hello Dobby Back to top
🌐
Typer
typer.tiangolo.com › tutorial › subcommands
SubCommands - Command Groups - Typer
Typer, build great CLIs. Easy to code. Based on Python type hints.