web-dev-qa-db-ja.com

Argparse:「x」が存在する場合、必須の引数「y」

次のような要件があります。

./xyifier --prox --lport lport --rport rport

引数proxには、action = 'store_true'を使用して、存在するかどうかを確認します。引数は必要ありません。ただし、-proxが設定されている場合、I require rportおよびlportも同様です。カスタム条件付きコーディングを作成せずにargparseでこれを行う簡単な方法はありますか?.

より多くのコード:

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', type=int, help='Listen Port.')
non_int.add_argument('--rport', type=int, help='Proxy port.')
89
asudhak

いいえ、相互に包括的オプションのセットを作成するオプションはargparseにはありません。

これに対処する最も簡単な方法は次のとおりです。

if args.prox and (args.lport is None or args.rport is None):
    parser.error("--prox requires --lport and --rport.")
85
borntyping

あなたは条件付きで必要な引数を持っていることについて話している。 @borntypingが言ったように、エラーを確認してparser.error()を実行するか、新しい引数を追加するときに--proxに関連する要件を適用することができます。

あなたの例の簡単な解決策は次のとおりです。

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', required='--prox' in sys.argv, type=int)
non_int.add_argument('--rport', required='--prox' in sys.argv, type=int)

このようにすると、requiredは、ユーザーが--proxを使用したかどうかに応じて、TrueまたはFalseを受け取ります。これにより、-lport-rportが互いに独立した動作をすることも保証されます。

41
Mira

parser.parse_known_args() メソッドを使用してから--lportおよび--rportが必須の場合の引数--proxが存在します。

# just add --prox arg now
non_int = argparse.ArgumentParser(description="stackoverflow question", 
                                  usage="%(prog)s [-h] [--prox --lport port --rport port]")
non_int.add_argument('--prox', action='store_true', 
                     help='Flag to turn on proxy, requires additional args lport and rport')
opts, rem_args = non_int.parse_known_args()
if opts.prox:
    non_int.add_argument('--lport', required=True, type=int, help='Listen Port.')
    non_int.add_argument('--rport', required=True, type=int, help='Proxy port.')
    # use options and namespace from first parsing
    non_int.parse_args(rem_args, namespace = opts)

また、最初の解析後に生成されたネームスペースoptsを指定し、残りの引数を2回目に解析できることに注意してください。そうすれば、最終的に、すべての解析が完了した後、すべてのオプションを備えた単一の名前空間が得られます。

欠点:

  • --proxは存在しませんが、他の2つの依存オプションは名前空間にも存在しません。ユースケースに基づいていますが、--proxが存在しない場合、他のオプションに何が起こるかは関係ありません。
  • パーサーは完全な構造を知らないため、使用法メッセージを変更する必要があります
  • --lportおよび--rportヘルプメッセージに表示されない
6
Aditya Sriram

lportが設定されていない場合、proxを使用しますか。そうでない場合、lportrportおよびprox引数を作成しないのはなぜですか?例えば.

parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports')

これにより、ユーザーが入力する手間が省けます。テストも同様に簡単ですif args.prox is not None: なので if args.prox:

5
hpaulj

受け入れられた答えは私にとって素晴らしい仕事でした!すべてのコードはテストなしで壊れているため、ここで受け入れられた答えをテストしました。 parser.error()argparse.ArgumentErrorエラーを発生させず、代わりにプロセスを終了します。 SystemExitをテストする必要があります。

pytestで

import pytest
from . import parse_arguments  # code that rasises parse.error()


def test_args_parsed_raises_error():
    with pytest.raises(SystemExit):
        parse_arguments(["argument that raises error"])

ユニットテスト付き

from unittest import TestCase
from . import parse_arguments  # code that rasises parse.error()

class TestArgs(TestCase):

    def test_args_parsed_raises_error():
        with self.assertRaises(SystemExit) as cm:
            parse_arguments(["argument that raises error"])

インスピレーション: nittestを使用したargparseのテスト-終了エラー

0
Daniel Butler