Ответ 1
Используйте настраиваемое действие:
import argparse
foo_default=None
class BarAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
didfoo=getattr(namespace,'foo',foo_default)
if(didfoo == foo_default):
parser.error( "foo before bar!")
else:
setattr(namespace,self.dest,values)
parser=argparse.ArgumentParser()
parser.add_argument('--foo',default=foo_default)
parser.add_argument('--bar',action=BarAction,help="Only use this if --foo is set")
#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())
Это можно сделать немного проще, чтобы поддерживать способ, если вы в порядке, опираясь на недокументированное поведение argparse:
import argparse
parser=argparse.ArgumentParser()
first_action=parser.add_argument('--foo',dest='cat',default=None)
class BarAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
didfoo=getattr(namespace,first_action.dest,first_action.default)
if(didfoo == first_action.default):
parser.error( "foo before bar!")
else:
setattr(namespace,self.dest,values)
parser.add_argument('--bar',action=BarAction,
help="Only use this if --foo is set")
#testing.
print parser.parse_args('--foo baz'.split())
print parser.parse_args('--foo baz --bar cat'.split())
print parser.parse_args('--bar dog'.split())
В этом примере мы получаем значение по умолчанию для foo
и его назначение из объекта действия, возвращаемого add_argument
(значение возвращаемого значения add_argument не документировано нигде, что я могу найти). Это все еще немного хрупко (если вы хотите указать ключевое слово type=
для аргумента --foo
, например).
Наконец, вы можете проверить sys.argv
перед синтаксическим разбором.
import sys
if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv):
parser.error("parameter1 must be given if parameter2 is given")
Это становится немного сложнее, если --parameter1
также может быть вызван --p1
, но вы получите эту идею. Затем вы можете использовать
if (set(sys.argv).intersection(('--p2',...)) and
not set(sys.argv).intersection(('--p1',...)))
Преимущество здесь в том, что он не требует какого-либо конкретного порядка. (--p2
не нужно следовать --p1
в командной строке). И, как и прежде, вы можете получить список командных строк, которые будут запускать ваше конкретное действие с помощью атрибута option_strings
, возвращаемого parser.add_argument(...)
. например.
import argparse
import sys
parser=argparse.ArgumentParser()
action1=parser.add_argument('--foo')
action2=parser.add_argument('--bar',
help="Only use this if --foo is set")
argv=set(sys.argv)
if (( argv & set(action2.option_strings) ) and
not ( argv & set(action1.option_strings) )):
#^ set intersection
parser.error(' or '.join(action1.option_strings)+
' must be given with '+
' or '.join(action2.option_strings))