私はできる限り多くの調査を行いましたが、特定のコマンドライン引数を特定の条件下でのみ必要とする最善の方法を見つけていません。この場合、他の引数が指定されている場合のみです。これが、非常に基本的なレベルでやりたいことです。
p = argparse.ArgumentParser(description='...')
p.add_argument('--argument', required=False)
p.add_argument('-a', required=False) # only required if --argument is given
p.add_argument('-b', required=False) # only required if --argument is given
私が見たことから、他の人は最後に自分のチェックを追加するようです:
if args.argument and (args.a is None or args.b is None):
# raise argparse error here
これをargparseパッケージ内でネイティブに行う方法はありますか?
私はしばらくの間、この種の質問に対する簡単な答えを探してきました。 '--argument'
がsys.argv
にあるかどうかを確認するだけでよいので、基本的に、コードサンプルでは次のようにすることができます。
import argparse
import sys
if __name__ == '__main__':
p = argparse.ArgumentParser(description='...')
p.add_argument('--argument', required=False)
p.add_argument('-a', required='--argument' in sys.argv) #only required if --argument is given
p.add_argument('-b', required='--argument' in sys.argv) #only required if --argument is given
args = p.parse_args()
このように、required
は、ユーザーが--argument
を使用したかどうかに応じて、True
またはFalse
を受け取ります。すでにテスト済みで、動作しているようで、-a
と-b
が相互に独立した動作をすることが保証されています。
--argument
のカスタムアクションを提供することでチェックを実装できます。これは、--argument
が使用されている場合に必要になる他のアクションを指定する追加のキーワード引数を取ります。
import argparse
class CondAction(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
x = kwargs.pop('to_be_required', [])
super(CondAction, self).__init__(option_strings, dest, **kwargs)
self.make_required = x
def __call__(self, parser, namespace, values, option_string=None):
for x in self.make_required:
x.required = True
try:
return super(CondAction, self).__call__(parser, namespace, values, option_string)
except NotImplementedError:
pass
p = argparse.ArgumentParser()
x = p.add_argument("--a")
p.add_argument("--argument", action=CondAction, to_be_required=[x])
CondAction
の正確な定義は、--argument
が何をすべきかによって異なります。ただし、たとえば、--argument
が通常の、引数を1つ取り、それを保存するタイプのアクションの場合、argparse._StoreAction
から継承するだけで十分です。
パーサーの例では、--a
オプション内の--argument
オプションへの参照を保存し、--argument
がコマンドラインに表示されると、required
フラグを設定します--a
からTrue
まで。すべてのオプションが処理されると、argparse
は、必須としてマークされたオプションが設定されていることを確認します。
特に_is None
_を使用したデフォルトのテストがニーズに合っている場合は、ポスト解析テストで問題ありません。
http://bugs.python.org/issue11588 _'Add "necessarily inclusive" groups to argparse'
_は、groups
メカニズム(mutual_exclusive_groupsの一般化)を使用して、このようなテストの実装を調べます。
UsageGroups
(相互に排他的)、xor
、and
、or
などのテストを実装するnot
のセットを作成しました。包括的だと思っていたのですが、それらの運用に関しては申し上げられませんでした。 (nand
が必要なようです-必要ありません。以下を参照してください)
このスクリプトは、基本的に解析後のテストを実装するカスタムTest
クラスを使用します。 _seen_actions
_は、解析で確認されたアクションのリストです。
_class Test(argparse.UsageGroup):
def _add_test(self):
self.usage = '(if --argument then -a and -b are required)'
def testfn(parser, seen_actions, *vargs, **kwargs):
"custom error"
actions = self._group_actions
if actions[0] in seen_actions:
if actions[1] not in seen_actions or actions[2] not in seen_actions:
msg = '%s - 2nd and 3rd required with 1st'
self.raise_error(parser, msg)
return True
self.testfn = testfn
self.dest = 'Test'
p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter)
g1 = p.add_usage_group(kind=Test)
g1.add_argument('--argument')
g1.add_argument('-a')
g1.add_argument('-b')
print(p.parse_args())
_
出力例は次のとおりです。
_1646:~/mypy/argdev/usage_groups$ python3 issue25626109.py --arg=1 -a1
usage: issue25626109.py [-h] [--argument ARGUMENT] [-a A] [-b B]
(if --argument then -a and -b are required)
issue25626109.py: error: group Test: argument, a, b - 2nd and 3rd required with 1st
_
usage
とエラーメッセージはまだ作業が必要です。そして、構文解析後のテストでできないことは何もしません。
_(argument & (!a or !b))
_の場合、テストでエラーが発生します。逆に、許可されているのは!(argument & (!a or !b)) = !(argument & !(a and b))
です。 nand
テストをUsageGroup
クラスに追加することで、次のようにケースを実装できます。
_p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter)
g1 = p.add_usage_group(kind='nand', dest='nand1')
arg = g1.add_argument('--arg', metavar='C')
g11 = g1.add_usage_group(kind='nand', dest='nand2')
g11.add_argument('-a')
g11.add_argument('-b')
_
使い方は(!()
を使用して「nand」テストをマークします):
_usage: issue25626109.py [-h] !(--arg C & !(-a A & -b B))
_
これは、汎用の使用グループを使用してこの問題を表現する最も短くて明確な方法だと思います。
私のテストでは、正常に解析される入力は次のとおりです。
_''
'-a1'
'-a1 -b2'
'--arg=3 -a1 -b2'
_
エラーを発生させることになっているものは次のとおりです。
_'--arg=3'
'--arg=3 -a1'
'--arg=3 -b2'
_
議論のために、私はこのような迅速で汚い解決策を考え出しました。前提:(1) '--help'はヘルプを表示し、必要な引数について文句を言わないようにする必要があります。(2)解析中ですsys.argv
p = argparse.ArgumentParser(...)
p.add_argument('-required', ..., required = '--help' not in sys.argv )
これは、特定の設定に合わせて簡単に変更できます。必要なポジション(コマンドラインで '--help'が指定されている場合は不要になります)については、次のようになります:[ポジションはrequired=...
キーワード引数!]
p.add_argument('pattern', ..., narg = '+' if '--help' not in sys.argv else '*' )
基本的に、これにより、コマンドラインで必要な 'pattern'の出現回数が、 '-help'が指定されている場合に1つ以上から0以上に変わります。
これは本当に@Miraの回答と同じですが、オプションが指定されているときに追加の引数が必要な場合に備えて、それを表示したいと思います。
たとえば、--option foo
が指定されている場合、--option bar
が指定されている場合は不要ないくつかの引数も必要です。
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--option', required=True,
help='foo and bar need different args')
if 'foo' in sys.argv:
parser.add_argument('--foo_opt1', required=True,
help='--option foo requires "--foo_opt1"')
parser.add_argument('--foo_opt2', required=True,
help='--option foo requires "--foo_opt2"')
...
if 'bar' in sys.argv:
parser.add_argument('--bar_opt', required=True,
help='--option bar requires "--bar_opt"')
...
それは完璧ではありません-たとえばproggy --option foo --foo_opt1 bar
はあいまいですが、私がそれを行うために必要なものについてはそうです。
http://bugs.python.org/issue11588 が解決されるまで、 nargs
を使用します:
p = argparse.ArgumentParser(description='...')
p.add_argument('--arguments', required=False, nargs=2, metavar=('A', 'B'))
このように、誰かが--arguments
、2つの値があります。
CLIの結果は読みにくいかもしれませんが、コードははるかに小さくなります。あなたは良いドキュメント/ヘルプでそれを修正することができます。