Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 3 years have passed since last update.

argaparseのおすすめ設定

Last updated at Posted at 2022-01-21

はじめに

仕事では、よくpythonのCLIを作っています。
awscliのようにAPIリクエストをラップするようなCLIや、ファイルを成形するようなCLIです。

pythonのコマンドラインパーサは、標準ライブラリのargparseだけでなくclickやfireやcleoなどがありますが、私はargparseを好んで利用しています。
argparseの知見が溜まってきたので、それを紹介します。

argparseのおすすめ設定

設定1: ヘルプメッセージの改善

以下の記事を参照。

設定2:バージョンの表示

長く利用するCLIならバージョン情報は必要になるので、バージョン情報は表示できるようにした方がよいです。

parser.add_argument("--version", action="version", version="%(prog)s 0.1.0")
$ python cli.py  --version
cli.py 0.1.0

※ poetryを使うと、pyproject.toml__version__.pyの2か所にバージョン情報を定義しなくてはいけないです。なんとか一元管理したいのですが、その方法が分かりません。

設定3:共通の引数を引数グループでまとめる

--debug--dry-runなど、コマンドの共通オプションになるものは、引数グループでまとめると分かりやすくなります。

def create_parent_parser():
    parent_parser = argparse.ArgumentParser(add_help=False)
    group = parent_parser.add_argument_group("global options")
    group.add_argument(
        "--dry-run", action="store_true", help="イメージを作らずに、イメージを作る権限があるかどうかをチェックする。"
    )
    group.add_argument("--version", action="version", version="%(prog)s 0.1.0")
    return parent_parser


def parse_args():
    parser = ArgumentParser(
        description=textwrap.dedent(
            """
            イメージを作成する。
            ``aws ec2 create-image`` コマンドを参考にした。
            """
        ).strip(),
        formatter_class=MyHelpFormatter,
        parents=[create_parent_parser()],
    )
$ python cli.py -h
...

optional arguments:
  -h, --help        show this help message and exit

  --name NAME       イメージの名前。
                    制約:3-128文字の英数字。

  --type {foo,bar}  イメージのタイプ。
                     * foo: FOO
                     * bar: BAR (default: bar)

global options:
  --dry-run         イメージを作らずに、イメージを作る権限があるかどうかをチェックする。

  --version         show program's version number and exit

argparse以外のおすすめ設定(のようなもの)

設定4:sphinxで生成したドキュメントにコマンドラインオプションの説明を記載する

CLIの使い方を知るにはpython cli.py --helpを実行すればよいのですが、この方法には以下の課題があります。

  • cli.pyをインストールしないと、コマンドのヘルプを確認できない
  • ターミナルに表示されたリンクやコードが見づらい

この課題を解決するには、sphinxで生成したドキュメントを公開すればよいのですが、コマンドライン引数の説明をargparseとsphinxドキュメントの両方に記載するのは面倒です。

sphinx-argparseを利用すると、sphinxで生成したドキュメントににコマンドラインオプションの説明を記載することができます。

TODO

設定5:複数の値/JSON文字列を受け取るコマンドライン引数はファイルからも受け取れるようにする

複数の値やJSON文字列を、コマンドラインから入力するのが面倒な場合があるので、ファイルからも値を入力できるようにするのが良いです。

ファイルパスをどのように渡すのがよいかは、CLIの世界観によって変わってくると思います。
awscliはfile://complete/path/to/fileのように、先頭にfile://が付いている場合はパスとみなしています。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-parameters-file.html

$ python cli.py --param a b c --json '{"x":1,"y":2}'
param.txt
a
b
c
foo.json
{
  "x": 1,
  "y": 2
}
$ python cli.py --param file://param.txt --json foo.json

なお、argparse.ArgumentParserクラスのfromfile_prefix_chars引数に値を指定すれば、ファイルから読み込むことができます。
ただし、コマンドライン引数ごとにファイルを読み込ませることはできないので、私は使っていないです。

clickでなくargparseを利用している理由

pythonのコマンドラインパーサの一つに、clickがあります。
clickは以下の機能が便利です。

  • サブコマンド化が簡単に作れる。
  • 関数にデコレータを付けるだけで、コマンドライン引数を定義できる。
  • テストランナーなどCLIに必要な機能がある程度揃っている。

しかし、clickはPOSIXに準拠しようとしているので、-から始まる引数は必須にできません。
POSIX規格では「オプションは"-" で始める」必要があります。

Click actually implements its own parsing of arguments and does not use optparse or argparse following the optparse parsing behavior. The reason it’s not based on argparse is that argparse does not allow proper nesting of commands by design and has some deficiencies when it comes to POSIX compliant argument handling.

ハイフンから始まる引数が必須にできないと、必須な引数はすべて位置引数にする必要があります。
位置引数で表現すると、かえって分かりづらくなるので、私はargparseを利用しています。

最後に

皆さんはどんなコマンドラインパーサを使っていますか?argparse? click? cleo, fire?

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?