2017-10-26 9 views
0

私はscript.pyに次のコードを持っている:argparseにどのようにデフォルトサブパーザを選択させるのですか?

import argparse 

parser = argparse.ArgumentParser() 
sp = parser.add_subparsers(dest='command') 
sp.default = 'a' 

a_parser = sp.add_parser('a') 
b_parser = sp.add_parser('b') 

a_parser.add_argument('--thing', default='thing') 
b_parser.add_argument('--nothing', default='nothing') 

args = parser.parse_args() 
print(args) 

私はこの3つの異なる方法を呼び出すことができます:私はをしたいする場合、私はゼロを提供することを示します。これで一つだけ問題があります

$ python3 script.py 
Namespace(command='a') 
$ python3 script.py a 
Namespace(command='a', thing='thing') 
$ python3 script.py b 
Namespace(command='b', nothing='nothing') 

をコマンドラインの引数は、a_parserが解析や処理を終了するものになります。明らかにそうではありません。sp.defaultはちょうどcommand='a'に設定されていますが、私が期待するものではありません。「ああ、ユーザーはコマンドラインで引数を提供しませんでしたが、これはa_parserで処理する必要があります。 Namespace(command='a', thing='thing')! "

私は方法がありますか?これはargparseで行いますか?私はいくつかのオプションを探しましたが、それらのどれも私が何をしているのかは実際には分からないようです。私は、3つの異なるArgumentParserを作成し、それぞれに引数を渡すことでいくつかのジグザグを行うことができると思いますが、それはちょっとグロスです。

もっと良いオプションはありますか?

+0

[cliff](https://pypi.python.org/pypi/cliff)や[click](http://click.pocoo.org/5/)のようなコマンドラインフレームワークを調べると、この種のデザインのサポート。 – larsks

+0

docoptをよく使う – Nickpick

答えて

2

最初は歴史的なメモです - サブパーザルはオプションではなく、まだPython2にはありません。 Py3でオプションであるという事実は、数年前に導入されたバグです。テストに必要な引数が変更され、サブパーザ(位置付けの一種)がクラックを通過しました。正しく実行された場合は、サブパーザを明示的に必須ではないものとして設定する必要があります。

サブパーザは、他の不要な引数のように動作しません。つまり、nargs='?'を持つもの、またはrequiredパラメータなしのフラグが付いたものです。

いずれにしても、sp.defaultcommand destに入れる値を定義しますが、a_parserは使用されません。そのcommand='a'は評価されません。

parse_known_argsを使用すると、残りの文字列をa_parserで切り捨てることができます。引数がなければ、私たちにできること

:(コマンドは「」が、何の「もの」ではない場合)

In [159]: args, extras = parser.parse_known_args([]) 
In [160]: args 
Out[160]: Namespace(command='a') 
In [161]: extras 
Out[161]: [] 

はその後、条件付き

In [163]: a_parser.parse_args(extras,namespace=args) 
Out[163]: Namespace(command='a', thing='thing') 

a_parserを実行します。しかし、私は、しようとした場合--thing値:それはsubparserとして '痛い' を解析しようと

In [164]: args, extras = parser.parse_known_args('--thing ouch'.split()) 
usage: ipython3 [-h] {a,b} ... 
ipython3: error: argument command: invalid choice: 'ouch' (choose from 'a', 'b') 

名前。メインパーサは--thing引数について何も知らない。

今日、他の質問で説明したように、トップレベルのパーサーは、「サブパーザ」コマンドに合ったもの(またはこの例ではエラーを発生させる)を見つけるまで、入力を解析します。次に、解析をサブパーザに渡します。後に解析を再開しません。

Add top level argparse arguments after subparser args

How to Set a Default Subparser using Argparse Module with Python 2.7

このPY2要求に対する私の答えはあなたのために働くかもしれません。まず、サブパーザーを持たないパーサーでparse_known_argsを実行し、サブパーザーを処理する2番目のパーサーを条件付きで実行します。

In [165]: firstp = argparse.ArgumentParser() 
In [166]: args, extras = firstp.parse_known_args('--thing ouch'.split()) 
In [167]: args 
Out[167]: Namespace() 

extrasが 'A' または 'b' は(あるいは単に直接sys.argv[1:]を見て)a_parserを呼び出されていない場合:

In [168]: extras 
Out[168]: ['--thing', 'ouch'] 
In [169]: a_parser.parse_args(extras) 
Out[169]: Namespace(thing='ouch') 

または欠落subparserコマンドを含めるようにextrasを変更します。

In [170]: extras = ['a']+extras 
In [171]: parser.parse_args(extras) 
Out[171]: Namespace(command='a', thing='ouch') 

いずれにしても、optionalサブパーサーは、​​ではうまく開発されていません。それは、よく考え出された機能ではなく、しばらく前に行われた変更の副作用です。

関連する問題