typer について
Typerは、現在の推奨方法でPythonのコマンドラインアプリを書くための公式スキルです。コマンド、型付き引数やオプションによる構成と、ヘルプの生成を案内します。
主な機能
- 01明示的なTyperアプリの作成
- 02複数コマンドの登録
- 03Annotatedによる引数宣言
- 04オプションと複数値の指定
- 05Richによるヘルプの整形
活用シーン
- 01Pythonコマンドラインアプリの構築
- 02サブコマンドと型付き引数の追加
- 03整形されたコマンドヘルプの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ fastapi/ typer --skill typerインストール後、Claude Code で/typerを入力して読み込まれたか確認します。
詳細
Typer
ベストプラクティスに従ってコードを記述し、新しいバージョンや機能に対応し続けるための、公式 Typer スキルです。
typer のインストール
仮想環境で、pip install typer(pip を使用)または uv pip install typer(uv を使用)を実行します。ライブラリやプロジェクトでは、pyproject.toml の依存関係に typer を追加します。
typer-slim や typer-cli はインストールしないでください。どちらも非推奨となっており、現在は単に typer をインストールするだけです。
Typer は Python 3.10 以降をサポートしています。
明示的な Typer アプリを使用する
汎用性を最大限に高めるため、typer.run を使用するのではなく、明示的な Typer アプリを作成してサブコマンドを登録します。
import typer
app = typer.Typer()
@app.command()
def hello():
print(f"Hello World")
if __name__ == "__main__":
app()
次のようにするのではなく、
# DO NOT DO THIS: Not extensible. Use Typer() instead.
import typer
def main():
print(f"Hello World")
if __name__ == "__main__":
typer.run(main)
アプリを実行する
ターミナルでアプリを実行するには、次のコマンドを実行します。
python main.py
Typer アプリに複数のコマンドを登録している場合は、コマンド名を追加する必要があります。
python main.py hello
自動生成されたヘルプドキュメントを表示するには、次のコマンドを実行します。
python main.py --help
または、Typer() の作成時に no_args_is_help を True に設定すると、引数を指定せずにコマンドを実行したときにヘルプが自動的に表示されます。
Annotated を使用する
CLI の引数とオプションの宣言には、常に Annotated スタイルを優先して使用してください。
これにより、Typer で使用できる追加のメタデータを渡せます。
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def hello(name: Annotated[str, typer.Argument()] = "World"):
# Note that name is an optional Argument, as a default is provided
print(f"Hello {name}")
if __name__ == "__main__":
app()
このプログラムはそのまま実行することも、名前を指定して実行することもできます。
python main.py
python main.py Rick
デフォルト値を設定する古い方法は、次のとおりです。
# DO NOT DO THIS: old style. Use Annotated instead.
@app.command()
def main(name: str = typer.Argument(default="World")):
# Note that name is an optional Argument, as a default is provided
print(f"Hello {name}")
同様に、古いスタイルでは省略記号(...)を使って、引数が必須であることを明示することもできました。
# DO NOT DO THIS: old style. Use Annotated without a default value instead.
@app.command()
def main(name: str = typer.Argument(default=...)):
# Note that name is now a required Argument
print(f"Hello {name}")
CLI オプション
CLI オプションは引数と同様の方法で宣言しますが、CLI ではハイフン 1 つ(1 文字の名前)またはハイフン 2 つ(完全な名前)を付けて呼び出します。
CLI オプション名は変数名から自動生成されるため、たとえば user_name は自動的に --user-name になります。
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def main(user_name: Annotated[str, typer.Option()]):
# On the CLI, the required user name can be specified with --user-name
print(f"Hello {user_name}")
if __name__ == "__main__":
app()
別の名前を指定する場合や、短縮形を追加する場合は、typer.Option で宣言します。
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def main(user_name: Annotated[str, typer.Option("--name", "-n")]):
# On the CLI, the required user name can be specified with -n or --name
print(f"Hello {user_name}")
if __name__ == "__main__":
app()
このプログラムは次のように実行できます。
python main.py -n "Rick"
python main.py --name "Morty"
複数の値を受け取る CLI オプション
CLI オプションをリストとして宣言すると、複数の値を受け取れます。
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def main(user: Annotated[list[str] | None, typer.Option()] = None):
if not user:
print(f"No users provided!")
raise typer.Abort()
for u in user:
print(f"Processing user: {u}")
if __name__ == "__main__":
app()
次のように実行できます。
python main.py --user Rick --user Morty --user Summer
Rich
デフォルトでは、Rich のカスタムマークアップ構文を使って色やスタイルを設定できます。たとえば、次のとおりです。
from rich import print
print("[bold red]Alert![/bold red] [green]Portal gun[/green] shooting! :boom:")
Typer では、CLI の引数や CLI オプションの docstring およびヘルプメッセージで Rich の書式設定を使用できます。
from typing import Annotated
import typer
app = typer.Typer(rich_markup_mode="rich")
@app.command()
def create(
username: Annotated[
str, typer.Argument(help="The username to be [green]created[/green]")
],
):
"""
[bold green]Create[/bold green] a new [italic]shiny[/italic] user. :sparkles:
This requires a [underline]username[/underline].
"""
print(f"Creating user: {username}")
@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].")
def delete(
username: Annotated[
str, typer.Argument(help="The username to be [red]deleted[/red]")
],
):
"""
Some internal utility function to delete.
"""
print(f"Deleting user: {username}")
if __name__ == "__main__":
app()
Rich の書式設定を無効にするには、Typer() アプリの作成時に rich_markup_mode を None に設定します。デフォルトでは(値を指定しない場合)、Rich の書式設定が有効になります。
Rich の Markdown
rich_markup_mode を "markdown" に設定して、docstring で Markdown を使用することもできます。
from typing import Annotated
import typer
app = typer.Typer(rich_markup_mode="markdown")
@app.command(help="**Delete** a user with *username*.")
def delete(
username: Annotated[
str, typer.Argument(help="The username to be **deleted** :boom:")
],
):
print(f"Deleting user: {username}")
if __name__ == "__main__":
app()
Click
Typer は当初、Click を基盤として構築されていました。しかし、バージョン 0.26.0 以降、Typer は Click を同梱しています。そのため、Click の拡張機能は使用しないでください。
Click 由来の Option および Argument の設定のうち、Typer では使用しないでください。これには、expose_value、shell_complete、show_choices、errors、prompt_required、is_flag、flag_value、allow_from_autoenv が含まれます。
これらを使用しているコードベースは、Typer の標準機能を使うようにリファクタリングしてください。