I am using argparse to build a command with subcommands:
mycommand [GLOBAL FLAGS] subcommand [FLAGS]
I would like the global flags to work whether they are before or after the subcommand. Is there a clean way to do this that doesn't involve repeating code?
For example:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
parser.add_argument('--disable') # This flag...
sp = subparsers.add_parser('compile')
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable') # Is repeated...
sp = subparsers.add_parser('launch')
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable') # over and over...
I want to do this for many flags, so repeating myself over and over seems... unpythonic.
This is a perfect use case for parents argparse feature:
Sometimes, several parsers share a common set of arguments. Rather than repeating the definitions of these arguments, a single parser with all the shared arguments and passed to parents= argument to ArgumentParser can be used.
Define a base parent ArgumentParser, add arguments that will be shared across subparsers. Then, add subparsers and set your base parser as a parent by providing parents keyword argument:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
base_subparser = argparse.ArgumentParser(add_help=False)
# define common shared arguments
base_subparser.add_argument('--disable')
sp = subparsers.add_parser('compile', parents=[base_subparser])
# define custom arguments
sp = subparsers.add_parser('launch', parents=[base_subparser])
# define custom arguments
Note that add_help=False here helps to avoid problems with conflicting help argument.
Also see: Python argparse - Add argument to multiple subparsers.
I see two issues in your example:
1) The use of '--disable' in both the parser and subparsers. Nested ArgumentParser
deals with that overlapping dest.
2) The repeated set of arguments in the subparsers. parents is certainly one way to simplify that. But you could easily write your own code:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
parser.add_argument('--disable', dest='main_disable') # This flag...
for name in ['compile', 'launch']:
sp = subparsers.add_parser(name)
sp.add_argument('zones', nargs='*')
sp.add_argument('--disable', dest=name+'_disable') # Is repeated...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With