2016/06/12

Day XXX: docopt の使い方

{docopt} は docstring(__doc__)からヘルプ作成や引数のパースを自動的に行うパッケージである。
PyPIのdocoptページに使い方は記載されており、Try docoptでテストもできる。
通常は何らかのソースコードからパーサを作成しドキュメントを生成する流れで考えてしまいがちだが、逆にドキュメントからパーサを作成するというコロンブスの卵的な発想から生まれたパッケージである。
ドキュメントと実際の実装を確実に同期することができるという意味で、非常に強力なパッケージであると考える。
使い方は基本的に docstring を書くだけである。
前回と同様に arith4 という sandbox パッケージ上で実装してみる。
arith4/arith4_command.py#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
pythonパッケージの使い方を練習するための簡単な四則演算コマンド

Usage:
  arith4_command [--max|--min|--plus|--times] [--head <num>|--tail <num>] (values <val> [<val>...]|files <file> [<file>...])
  arith4_command -h|--help
  arith4_command -v|--version

Arguments:
  values <val> [<val>...]   値を引数として直接渡す場合
  files <file> [<file>...]  値を1行ひとつの値が書かれたファイルで渡す場合

Options:
  --max                     与えられた値の最大値を返す(デフォルト)
  --min                     与えられた値の最小値を返す
  --plus                    与えられた値を全て足した値を返す
  --times                   与えられた値を全て掛けた値を返す
  --head <num>              与えられた値の先頭<num>個を対象とする
  --tail <num>              与えられた値の最後<num>個を対象とする
  -h,--help                 ヘルプを表示
  -v,--version              バージョン番号を表示
"""

import os
import sys
from docopt import docopt, DocoptExit

...(snip)...

def arith4_command():
    try:
        args = docopt(__doc__, argv=None, help=True, version=arith4.__version__, options_first=False)
    except DocoptExit as e:
        print("Invalid arguments or options", file=sys.stderr)
        print(e, file=sys.stderr)
        sys.exit(1)
    except SystemExit:
        sys.exit(0)
here documentのに、ライプラリやコマンドの説明、ライブラリやコマンドの Usage、必須の引数である Arguments、任意のオプションである Options を書く。
これらの順番は任意のもので構わない。
ただし、Usage, Arguments, Options の先頭にはぞれぞれ「Usage:」「Arguments:」「Options:」の行を入れなければならない。
「Usage:」「Arguments:」「Options:」の大文字小文字は問わない。
「Usage:」「Arguments:」「Options:」は here document の先頭か、それらの前に1行開けないと、正しく判別されない。

Usageの書式は以下である。
  • 1文字のオプション名は '-'、複数文字のオプション名は '--' が文字列の前に来る
  • [] で囲まれたものは、必須ではないオプション
  • () で囲まれたものは、必須である引数をグループ化したもの
  • | は or の意味
  • <> で囲まれたものは、その位置(特定の引数・オプションの後)によって取り込まれる変数
  • ハイフンが前に無く、<>で囲まれてもいない文字列は、そのままの文字列が与えられることが必要とされている引数
  • <x>... と後にピリオドが3個付いているものは、その変数の0個以上の繰り返しを表す
上記の例の Usage は以下の意味である。
  • arith4_command は--max, --min, --plus, --times のどれかのオプションを受け取ることが出来る
    • これらのうちどれかひとつであり、これらをどれも指定しなくても良いが、複数を指定することはできない
  • arith4_command は --head もしくは --tail どれかのオプションを受け取ることが出来る
    • --head も --tail も、その後に変数をひとつ指定しなければならない
  • arith4_command は、values もしくは files という文字列の引数を指定することが必須であり、その後にひとつ以上の変数を指定しなければならない
    • values <val>... であると、... は変数の0個以上の繰り返しであるため、変数<val>を全く指定しなくても良いとなってしまう
    • <val> <val>... と指定することで、1個以上の繰り返しを指定できる
    • <val>... も <val> <val>... も、与えられた変数は同じ配列に格納される
Usage は複数行に書くことができ、複雑なパターンにも対応することができる。
上記の例ではヘルプとバージョンを別の行に記したが、() にまとめた values と files を分けて、以下の様に書くことも出来る。
arith4/arith4_command.py
"""
pythonパッケージの使い方を練習するための簡単な四則演算コマンド

Usage:
  arith4_command [--max|--min|--plus|--times] [--head <num>|--tail <num>] values <val> [<val>...]
  arith4_command [--max|--min|--plus|--times] [--head <num>|--tail <num>] files <file> [<file>...]
  arith4_command -h|--help
  arith4_command -v|--version

Arguments:
...(snip)...
"""
こうして作成した here document を元に、引数をパースする関数が docopt() である。
docopt()のAPIargs = docopt(__doc__, argv=None, help=True, version=arith4.__version__, options_first=False)
ひとつ目の引数がdocoptに対応するように書かれた文字列(この場合は here document)である。以降はオプション。
  • docopt はデフォルトで sys.argv[1:] に相当するものをパースするが、argv に指定したものをパースさせることもできる
    デフォルトは None(=sys.argv[1:]をパースする)
  • help はヘルプを表示させるか否か。
    デフォルトで True
  • versionは文字列を指定して、-v | --version オプションで表示させるもの
    デフォルトは None(=何も表示しない)
  • options_first は、True にすると、ハイフン無しの(文字列がそのまま指定されることが望まれている)オプション以降に、ハイフン付きのオプションを付けても、それは無視されるという POSIX 仕様に基づくもの
    デフォルトは False(=順番は関係ない)
    • 例えば arith4_command --head 2 values 1 2 3 4 5 --plus という呼び出しをして、options_first = True の場合、'--head 2' は有効であるが '--plus' は無視される
docopt() のエラーである DocoptExit はパースした結果が docopt のフォーマット(この場合 here document)と不一致の場合に送出され、Usage の内容が格納されている。
また、SystemExit は --help もしくは --version の場合に送出される。(なので、コマンドの場合は except で catch しなくても構わない)

docopt() はパースした結果を辞書の形で出力する。
例えば、arith4_command --plus --tail 2 values 1 2 4 5 6 という呼び出しをした場合、帰り値(args)は以下のようになる。
arith4_command --plus --tail 2 values 1 2 4 5 6 の場合の args{
  '--head': None,
  '--help': False,
  '--max': False,
  '--min': False,
  '--plus': True,
  '--tail': '2',
  '--times': False,
  '--version': False,
  '<file>': [],
  '<val>': ['1', '2', '4', '5', '6'],
  'files': False,
  'values': True
}
  • 引数および変数を伴わないオプションは、その名前を key として value は bool(True or False)となる
  • 変数を伴うオプションとその変数は、オプションの名前を key とし、value は変数の文字列となる
    • 指定されなかった場合は None になる
  • 引数に対する変数、もしくは引数を伴わず変数のみを指定されている場合は、<>付きの名前を key とする value に格納される
  • 複数指定されている変数は自動的に配列の形に格納される
  • 指定されていようがいまいが、全ての引数・オプション(と引数を伴わない変数)が辞書の key に登録されている

0 件のコメント:

コメントを投稿