72

argparse に 2 つの引用符の間を単一の引数として認識させる方法はありますか? ダッシュが表示され続け、それが新しいオプションの開始であると想定しているようです

私は次のようなものを持っています:

mainparser = argparse.ArgumentParser()
subparsers = mainparser.add_subparsers(dest='subcommand')
parser = subparsers.add_parser('queue')
parser.add_argument('-env', '--extraEnvVars', type=str,
                        help='String of extra arguments to be passed to model.')
...other arguments added to parser...

しかし、私が実行すると:

python Application.py queue -env "-s WHATEVER -e COOL STUFF"

それは私に与えます:

Application.py queue: error: argument -env/--extraEnvVars: expected one argument

最初のダッシュを省略してもまったく問題なく動作しますが、ダッシュを含む文字列を渡すことができることが重要です。\ でエスケープしようとしましたが、これにより成功しますが、引数文字列に \ が追加されます 誰でもこれを回避する方法を知っていますか? これは、-s がパーサーの引数であるかどうかに関係なく発生します。

編集: Python 2.7 を使用しています。

EDIT2:

python Application.py -env " -env"

完全に正常に動作しますが、

python Application.py -env "-env"

ではない。

EDIT3:これは実際にはすでに議論されているバグのようです:http://www.gossamer-threads.com/lists/python/bugs/89529http://python.6.x6.nabble.com/issue9334- argparse-does-not-accept-options-take-arguments-beginning-with-dash-regression-from-optp-td578790.html . これは 2.7 のみにあり、optparse にはありません。

EDIT4: 現在開いているバグ レポートは次のとおりです: http://bugs.python.org/issue9334

4

7 に答える 7

25

この問題については、http://bugs.python.org/issue9334で詳しく説明されています。活動のほとんどは 2011 年に行われました。昨年パッチを追加しましたが、パッチのバックログがかなりありargparseます。

問題となっているのは、 のような文字列の潜在的なあいまいさ'--env'、または"-s WHATEVER -e COOL STUFF"引数を取るオプションに続く場合です。

optparse単純な左から右への解析を行います。1つ目--envは、引数を 1 つ取るオプション フラグであるため、見た目に関係なく、次の引数を消費します。 argparse一方、文字列を 2 回ループします。最初に、それらを 'O' または 'A' (オプション フラグまたは引数) として分類します。2 番目のループでは、relike パターン マッチングを使用して変nargs数値を処理し、それらを消費します。OOこの場合、2 つのフラグがあり、引数がないように見えます。

使用時の解決策argparseは、引数文字列がオプション フラグと混同されないようにすることです。ここ (およびバグの問題) で示されている可能性は次のとおりです。

--env="--env"  # clearly defines the argument.

--env " --env"  # other non - character
--env "--env "  # space after

--env "--env one two"  # but not '--env "-env one two"'

それ自体'--env'はフラグのように見えますが (引用されている場合でも、 を参照sys.argv)、他の文字列が続く場合はそうではありません。しかし、'-e' フラグとそれに続く文字列 (またはさらに多くのオプション)"-env one two"として解析できるため、問題があります。['-e','nv one two']

--また、後続のすべての文字列を引数としてnargs=argparse.PARSER強制的に表示するためにも使用できます。argparseただし、それらは引数リストの最後でのみ機能します。

モードを追加するために issue9334 に提案されたパッチがありargs_default_to_positional=Trueます。このモードでは、パーサーは、定義された引数と明確に一致する場合にのみ、文字列をオプション フラグとして分類します。したがって、「--env --one」の「--one」は引数として分類されます。しかし、'--env --env' の 2 番目の '--env' は、依然としてオプション フラグとして分類されます。


関連する事例の拡大

ダッシュ ("-") で始まる引数値で argparse を使用する

parser = argparse.ArgumentParser(prog="PROG")
parser.add_argument("-f", "--force", default=False, action="store_true")
parser.add_argument("-e", "--extra")
args = parser.parse_args()
print(args)

生産する

1513:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra='--foo one', force=False)
1513:~/mypy$ python3 stack16174992.py --extra "-foo one"
usage: PROG [-h] [-f] [-e EXTRA]
PROG: error: argument -e/--extra: expected one argument
1513:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra='-bar one', force=False)
1514:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra='one', force=True)

"-foo one" の場合は、がフラグと指定-fooされていないエクストラとして解釈されるため、失敗します。これは、として解釈-fできるのと同じアクションです。-fe['-f','-e']

nargsREMAINDER(not )に変更するとPARSER、その後のすべて-eがそのフラグの引数として解釈されます。

parser.add_argument("-e", "--extra", nargs=argparse.REMAINDER)

すべてのケースが機能します。値はリストであることに注意してください。引用符は必要ありません。

1518:~/mypy$ python3 stack16174992.py --extra "--foo one"
Namespace(extra=['--foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-foo one"
Namespace(extra=['-foo one'], force=False)
1519:~/mypy$ python3 stack16174992.py --extra "-bar one"
Namespace(extra=['-bar one'], force=False)
1519:~/mypy$ python3 stack16174992.py -fe one
Namespace(extra=['one'], force=True)
1520:~/mypy$ python3 stack16174992.py --extra --foo one
Namespace(extra=['--foo', 'one'], force=False)
1521:~/mypy$ python3 stack16174992.py --extra -foo one
Namespace(extra=['-foo', 'one'], force=False)

argparse.REMAINDER'*' に似ていますが、フラグのように見えるかどうかに関係なく、後続のすべてを取得します。 最初に like 引数argparse.PARSERを期待するという点で、'+' に似ています。使うpositionalものnargsです。subparsers

この使用法REMAINDERは文書化されています https://docs.python.org/3/library/argparse.html#nargs

于 2014-02-19T22:54:18.763 に答える
19

python tst.py -e ' -e blah'非常に簡単な回避策として、スペースで引数を開始できます。必要に応じて、通常の状態に戻すlstrip()オプションがあります。

または、最初の「サブ引数」も元の関数の有効な引数でない場合は、何もする必要はありません。つまり、python tst.py -e '-s hi -e blah'機能しない唯一の理由-sは、 が有効なオプションであるためですtst.py

また、現在非推奨となっているoptparseモジュールも問題なく動作します。

于 2013-04-23T17:13:31.343 に答える
1

スクリプトを optparse から argparse に移植しました。このスクリプトでは、特定の引数が負の数で始まる可能性のある値を取りました。「=」記号を使用せずにスクリプトが多くの場所で使用され、負の値をフラグに結合しているため、この問題に遭遇しました。こことhttp://bugs.python.org/issue9334の議論を読んだ後、引数が 1 つの値しかとらず、後続の引数 (つまり、欠落した値) を値として受け入れるリスクがないことがわかりました。FWIW、私の解決策は、引数を前処理し、問題のある引数を '=' で結合してから parse_args() に渡すことでした:

def preprocess_negative_args(argv, flags=None):
    if flags is None:
        flags = ['--time', '--mtime']
    result = []
    i = 0
    while i < len(argv):
        arg = argv[i]
        if arg in flags and i+1 < len(argv) and argv[i+1].startswith('-'):
            arg = arg + "=" + argv[i+1]
            i += 1
        result.append(arg)
        i += 1
    return result

このアプローチは、少なくともユーザーによる変更を必要とせず、明示的に負の値を許可する必要がある引数のみを変更します。

>>> import argparse
>>> parser = argparse.ArgumentParser("prog")
>>> parser.add_argument("--time")
>>> parser.parse_args(preprocess_negative_args("--time -1d,2".split()))
Namespace(time='-1d,2')

先頭にダッシュを付けて値を明示的に許可する引数を argparse に伝える方が便利ですが、このアプローチは合理的な妥協のように思えます。

于 2020-10-15T20:22:28.293 に答える
1

同様の問題。そして、スペースを「\」に置き換えることでこれを解決します。例えば:


python Application.py "cmd -option"
に置き換え
python Application.py "cmd\ -option"ます。
あなたの問題についてはわかりません。

于 2021-11-12T01:58:41.767 に答える