はじめに
『かがみの孤城』Blu-ray&DVD発売中🎉
全世代にお勧めしたい作品! nikkieです。
Pythonでコマンドラインツールが作れる標準ライブラリのargparseについて、最近知った小ネタをアウトプットします。
目次
- はじめに
- 目次
- argparseでコマンドラインツールが作れる!
- コマンドのバージョンを確認したい
- バージョンを確認できるようにしたスクリプト
- 部分解析を知ったのはpysenのソースコードリーディング
- 終わりに
argparseでコマンドラインツールが作れる!
過去のエントリでも取り上げました。
指定した単語を指定した回数繰り返すコマンドラインツールです1。
import argparse parser = argparse.ArgumentParser() parser.add_argument("string") parser.add_argument("num", type=int, nargs="?", default=2) args = parser.parse_args() print(args.string * args.num)
Python 3.11.1で動作確認しています。
% # 繰り返し回数を指定しないと2回繰り返す(デフォルト値) % python repeat.py こころ こころこころ % # 繰り返し回数を指定する例 % python repeat.py こころ 5 こころこころこころこころこころ
コマンドのバージョンを確認したい
身の回りのコマンドを思い出すと、python
やgit
など--version
でバージョンが確認できますよね。
バージョンを確認した時はコマンドのメイン処理は実行されません。
これを上記のrepeat.py
でも実現したいと思いました。
引数を追加してみると
+import sys import argparse parser = argparse.ArgumentParser() parser.add_argument("string") parser.add_argument("num", type=int, nargs="?", default=2) +parser.add_argument("--version", action="store_true") args = parser.parse_args() +if args.version: + print("version 0.1.0") + sys.exit(0) print(args.string * args.num)
% python repeat.py --version usage: repeat.py [-h] [--version] string [num] repeat.py: error: the following arguments are required: string
あれ、バージョンが表示されない...
引数が足りないというエラーです。
なぜなら、string引数(位置引数。必須)を指定していないからです。
バージョンを表示したいだけなので、string引数の指定は不要にしたいです。
バージョンを確認できるようにしたスクリプト
以下のスクリプトで実現できます。
% python repeat.py --version version 0.1.0 % python repeat.py こころ こころこころ % python repeat.py こころ 5 こころこころこころこころこころ
ポイントは、部分解析!
バージョンの引数のために別のArgumentParser
を追加し、それで部分解析をします。
version_parser = argparse.ArgumentParser(add_help=False) version_parser.add_argument("--version", action="store_true") args, unknown = version_parser.parse_known_args()
https://docs.python.org/ja/3/library/argparse.html#partial-parsing
ときどき、スクリプトがコマンドライン引数のいくつかだけを解析し、残りの引数は別のスクリプトやプログラムに渡すことがあります。こういった場合、 parse_known_args() メソッドが便利です。
これは parse_args() と同じように動作しますが、余分な引数が存在してもエラーを生成しません。
実装としては
parse_known_args()
が返したargs
から--version
が指定されていたらバージョンを出力してコマンドを終了--version
が指定されていなければ、unknown
(引数からなるリスト)をコマンド本体のパーサでパース
としています。
ヘルプメッセージの調整
細かな点ですが、コマンド本体のパーサのparents
引数にバージョンの引数のためのパーサを指定しているのもポイント!
parser = argparse.ArgumentParser(parents=[version_parser])
これにより、バージョン確認のオプションもヘルプメッセージに含まれます。
% python repeat.py -h usage: repeat.py [-h] [--version] string [num] positional arguments: string num options: -h, --help show this help message and exit --version
https://docs.python.org/ja/3/library/argparse.html#parents
ときどき、いくつかのパーサーが共通の引数セットを共有することがあります。それらの引数を繰り返し定義する代わりに、すべての共通引数を持ったパーサーを ArgumentParser の parents= 引数に渡すことができます。
一番親になるパーサーに add_help=False を指定していることに注目してください。
比較のため、指定しない場合のヘルプメッセージです(parser = argparse.ArgumentParser()
)。
--version
の指定については記載がありませんね。
% python repeat.py -h usage: repeat.py [-h] string [num] positional arguments: string num options: -h, --help show this help message and exit
部分解析を知ったのはpysenのソースコードリーディング
https://github.com/pfnet/pysen/blob/0.10.4/pysen/cli.py#L265-L270
parser = _setup_manifest_parser() args, unknown = parser.parse_known_args() if args.version: _show_version() sys.exit(0)
終わりに
バージョンを確認するオプションを持ったコマンドラインツールをargparseで作る方法をアウトプットしました。
- 単一のArgumentParserで実現しようとすると、
--version
と合わせて必須引数の指定も必要になってしまう😢 - そこで別のArgumentParser + 部分解析(
parse_known_args
)- ArgumentParser初期化時の
parents
引数を使ってヘルプメッセージにオプションも追加できる!
- ArgumentParser初期化時の
作り方がわかったことで、python --version
やgit --version
と指定したときにバージョンだけが表示される(コマンド本体は実行されない)という作りって実は工夫がいるんだなと見逃していた点に気付きました。
こころちゃんこころちゃんこころちゃんこころちゃんこころちゃんこころちゃんこころちゃんこころちゃんこころちゃんこころちゃん