CLIしたい(typer
)
$ pip3 install typer[all]
1# パッケージ/cli.py
2import typer
3
4app = typer.Typer()
5
6@app.command()
7def hello(name: str):
8 print(f"Hello {name}")
9
10
11@app.command()
12def goodbye(name: str, formal: bool = False):
13 if formal:
14 print(f"Goodbye Ms. {name}. Have a good day.")
15 else:
16 print(f"Bye {name}!")
17
18if __name__ == "__main__":
19 app()
Typerを使うと、サブコマンド付きのCLIをすぐに作ることができます。
上記のサンプルは、公式ドキュメントのAn example with two subcommands - Typerにあるコードです。
とりあえずこのサンプルコードをcli.py
のようなファイルにコピペして動かしてみるだけで、使い方がわかると思います。
これまで、CLIを作るときの引数/オプション解析は、定番のPython標準argparse
パッケージを使っていましたが、サブコマンドを作るのはちょっと大変な印象でした。
(やってみようと思って調べたことはありますが実際に作ったことはない・・・)
Typer
は、引数とオプション、コマンドの説明も、いつもの関数を作る作業の延長ででき、非常に簡単だと感じました。
コマンドしたい(typer.Argument
/ typer.Option
)
1import typer
2from typing_extensions import Annotated
3
4def vth(
5 """
6 コマンドの説明
7 """
8 ch Annotated[int, typer.Argument(help="チャンネル番号")],
9 vth: Annotated[int, typer.Argument(help="スレッショルド値")],
10 max_retry: Annotated[int, typer.Option(help="リトライ数")] = 3,
11 load_from: Annotated[str, typer.Option(help="設定ファイル名")] = "daq.toml"
12 ):
13 pass
14
15if __name__ == "__main__":
16 typer.run(vth)
コマンドとして実行したい関数名をtyper.run
に渡します。
関数のdocstring
がコマンドの説明になります。
typer.Argument
で引数を設定できます。
typer.Option
でオプション引数を設定できます。
typing_extensions.Annotated
で引数の説明を追加できます。
追加方法などは、ドキュメントを参照してください。
ヒント
typer.Argument
/ typer.Option
と
デフォルト値のあり / なしを考えると
以下の表のような引数名のパターンが考えられます。
デフォルト値なし |
デフォルト値あり |
|
---|---|---|
|
CLI arguments |
optional CLI arguments |
|
required CLI options |
CLI options |
通常は、 CLI arguments(必須の位置引数)、 CLI options(オプション引数) のみのコマンドを設計するとよいと思います。
ただし、 optional CLI arguments(位置引数なのにオプション)、 required CLI options(オプション引数なのに必須) も、名前がちょっとおかしい気がしますが、定義できるようになっています。
サブコマンドしたい(@app.command
)
1import typer
2
3app = typer.Typer()
4
5@app.command()
6def vth(
7 """
8 コマンドの説明
9 """
10 ch Annotated[int, typer.Argument(help="チャンネル番号")],
11 vth: Annotated[int, typer.argument(help="スレッショルド値")],
12 max_retry: Annotated[int, typer.argument(help="リトライ数")] = 3,
13 load_from: Annotated[str, typer.argument(help="設定ファイル名")] = "daq.toml"
14 ):
15 pass
16
17if __name__ == "__main__":
18 app()
@app.command
デコレーターでサブコマンドを定義できます。
注釈
app
の部分は任意のオブジェクト名を使用できます。
上記のサンプルではapp = typer.Typer()
を作成しているため、デコレーターは@app.command
になります。
出力に色をつけたい(from rich import print
)
1import typer
2from rich import print
3
4...(省略)...
rich
パッケージのprint
を使うと、出力を色付けできます。
色付けの詳細や、その他の表示形式はドキュメントを参照してください。
中断/終了したい(typer.Exit
)
1@app.command()
2def コマンド名(引数):
3 if 引数がおかしい条件:
4 logger.error(f"値が正しくないです : {引数}")
5 typer.Exit()
Typer
を使うと、引数のバリデーションを柔軟に書くことができます。
引数の値が正しくない場合に終了する場合、typer.Exit
が使えます。
わざわざimport sys
してsys.exit
する必要がないので便利です。
PoetryでCLIしたい
1# pyproject.toml
2
3[tool.poetry.scripts]
4CLI名 = "パッケージ.cli:app"
Poetry
を使って自作CLIを作成する場合は、pyproject.toml
の[tool.poetry.scripts]
セクションに記述します。
詳しくは公式ドキュメントのBuilding a package - Typerを参照してください。