In my python script, I want to be able to use an optional input parameter only when another optional parameter has been specified. Example:
$ python myScript.py --parameter1 value1 $ python myScript.py --parameter1 value1 --parameter2 value2
But NOT:
$ python myScript.py --parameter2 value2
How do I do this with argparse?
Thanks!
Use a custom action:
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())
This can even be done in a little easier to maintain way if you're OK with relying on some undocumented behavior of 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())
In this example, we get the default for foo and it's destination from the action object returned by add_argument (add_argument's return value isn't documented anywhere that I can find). This is still a little fragile (If you want to specify a type= keyword to the --foo argument for example).
Finally, you can check sys.argv before parsing.
import sys if ("--parameter2" in sys.argv) and ("--parameter1" not in sys.argv): parser.error("parameter1 must be given if parameter2 is given")
This gets a little more tricky if --parameter1 could also be triggered by --p1, but you get the idea. Then you could use
if (set(sys.argv).intersection(('--p2',...)) and not set(sys.argv).intersection(('--p1',...)))
The advantage here is that it doesn't require any particular order. (--p2 doesn't need to follow --p1 on the commandline). And, as before, you can get the list of command strings that will trigger your particular action via the option_strings attribute returned by parser.add_argument(...). e.g.
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 &