Python Nested ArgumentParser Arguments

I want to create an argument parser with the following signature:

./myapp [-a [-b BVAL] | -c]

In other words, the user can provide the -b BVAL argument only if he provides the -a argument.

It is very easy to create a mutually exclusive group -a and -c , but I cannot figure out how to create a relationship allow -b only if -a provided

+4
source share
4 answers

Docopt does it the way I wanted. Awesome!

 docopt('./myapp [-a [-b BVAL] | -c]') 
+4
source

You can inherit from ArgumentParser to add some custom functions. I am throwing an exception here, but you can change this to implement whatever you want. Just change the on_dependency_error() method to suit your needs.

 from argparse import ArgumentParser class FancyParser(ArgumentParser): # {'b': 'a'} Where b depends on a dependencies = {} def on_dependency_error(self, arg, depends_on): raise FancyParser.DependencyError( 'Argument %s depends on %s' % (arg, depends_on)) def add_argument(self, *args, **kwargs): depends_on = kwargs.get('depends_on') if depends_on: self.dependencies[kwargs.get('dest') or args[0]] = depends_on del kwargs['depends_on'] return super(FancyParser, self).add_argument(*args, **kwargs) def parse_args(self, *args, **kwargs): args = super(FancyParser, self).parse_args(*args, **kwargs) for arg, depends_on in self.dependencies.iteritems(): if getattr(args, arg) and not getattr(args, depends_on): self.on_dependency_error(arg, depends_on) return args class DependencyError(Exception): def __init__(self, *args, **kwargs): return super(FancyParser.DependencyError, self).__init__(*args, **kwargs) 

Then you can use it like this:

 args = ['-a', '-b', 'BVAL', '-c'] parser = FancyParser() parser.add_argument('-a', dest='a', action='store_true') parser.add_argument('-b', dest='b', depends_on='a') parser.add_argument('-c', dest='c', action='store_true') try: parser.parse_args(args) except FancyParser.DependencyError as e: # Whatever here... pass 
+5
source

This is not exactly what you are looking for, but is it possible that you can use add_subparsers() ( doc )?

Do something like:

 import argparse parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(help='sub-command help') a = subparsers.add_parser('a') c = subparsers.add_parser('c') a.add_argument('b') 
+2
source

If you do not want to use subparameters, you can independently process the values โ€‹โ€‹of your arguments using parser.error.

 import argparse parser = argparse.ArgumentParser() parser.add_argument('-a', dest='a', default='') # you can use other defaults surely parser.add_argument('-b', dest='b', default='') parser.add_argument('-c', dest='c', default='') args = parser.parse_args() if args.b and not args.a: parser.error("Option 'b' can't be specified without 'a'") 

But still consider using subparameters in case you can extend the logic

+2
source

All Articles