rcmdnk's blog

A Rulebook for Arguments (English Edition)

Brew-file はPythonのスクリプトで出来てますが、 その中で使ってるArgumentParserについて 気になったところがあったのでそれを直したことについて。

ArgumentParserのparse_known_args

Pythonのargparse.ArgumentParser はその名の通り引数を解析してくれれるものです。

1
2
3
4
5
6
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("-a", "--aaa", action="store", dest="aaa")
>>> ns = parser.parse_args(['-a', 'test'])
>>> print ns
Namespace(aaa='test')

みたいな事をして引数を解析してくれます。 スクリプトの中で引数なしでparse_argsを呼べば スクリプトの引数を解析してくれて名前空間オブジェクトを返してくれます。

ここで、定義されたもの以外を与えると

1
2
3
>>> ns = parser.parse_args(['-a', 'test', '-b'])
usage: [-h] [-a AAA]
: error: unrecognized arguments: -b

となりエラーになります。

ただ、例えばファイル名を複数渡したりしたい時に、 残りの文字列は全てファイル名として認識、みたいなことを したい時には引数をそのまま渡したい時も有ります。

一部はArgumentParserで解析してもらって残りをそのまま渡すには parse_known_argsという関数を使う事が出来ます。

1
2
3
4
5
>>> (ns, args) = parser.parse_known_args(['-a', 'test', '-b'])
Namespace(aaa='test')
>>> print args
['-b']
>>>

と言った感じに、parse_known_argsは 引数解析結果の名前空間オブジェクトと、 残りの引数解析で解析できなかったものを配列で返してくれます。

これで残りの引数を別のArgumentParserに持って行ったり そのまま使ったりすることが可能です。

ArgumentParserのsubparsers

ArgumentParserではサブコマンドを作ることが出来ます。

1
2
3
4
5
6
7
8
9
>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("-a", "--aaa", action="store", dest="aaa")
>>> subparsers = parser.add_subparsers()
>>> subparser0 = subparsers.add_parser("bbb")
>>> subparser0.add_argument("-c", "--ccc", action="store", dest="ccc")
>>> ns = parser.parse_args(['bbb', '-c', 'subparsertest'])
>>> print ns
Namespace(aaa=None, ccc='subparsertest')

と言った感じで、bbbという引数を与えた後にさらに bbb用の引数解析が行える様になります。

ここで、引数に関係無いものを入れてparse_known_argsを 使おうとすると、 Python 2.7.7以降だと問題なく解析できなかったものは配列として返ってきます。

ですが、OS X 10.10デフォルトの2.7.6で試すと、

1
2
3
>>> (ns, args) = parser.parse_known_args(['bbb', '-c', 'subparsertest', 'X'])
usage: [-h] [-a AAA] {bbb} ...
: error: unrecognized arguments: X

の様にエラーになってしまいます。

これまでMacではHomebrewで新しいPythonを入れてそれを使ってたので 気付きませんでしたが、 Pythonの入れ替えとかしてる時にちょっとおかしな動きをしてたと 思ったらこれが原因でした。

探してみるとこれは2010年にIssueになってて解決されています。

Issue 9340: argparse parse_known_args does not work with subparsers - Python tracker

ただ、 RELEASENOTE とか見てもこれがいつ入ったのかは載ってなくてよく分かりません。

とりあえず今あるMacの2.7.6だとダメで Homebrewで入れた2.7.7以降だと大丈夫そうだと言うことだけ。 3.X系ではどこで入ったのか分かりませんが、取り敢えず 最新のなら大丈夫そう、といった感じ。

Brew-fileでの問題解決

Brew-file では通常は余計な引数を取ることは無いので そもそもエラーに成っても良いのですが、 brew file brew ...のコマンドで、brewコマンドを実行しつつ 実行後にBrewfileをアップデートする、といった時が問題になります。 (2つ目のbrew以降の引数をそのまま渡したいので)

さらに、これを/etc/brew-wrapの中でデフォルトbrewコマンドを ラップして使うようにしてるので PythonがMacデフォルトのままだとbrew install等のコマンドが 使えなくなってしまいます。

ということで、取り敢えずラッパー関数の中で Pythonのバージョンを見て 2.6.6の場合には直接brewコマンドを実行する様変更を行いました。

homebrew-file/brew-wrap

Sponsored Links
Sponsored Links

« HomebrewでPythonをインストールした際のpipのアップデートの注意 ローカルインストールしたautomakeを使って./autogen.shから./configureする際のトラブル解決 »

}