Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permit argparse global flags after subcommand

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.

like image 222
TomOnTime Avatar asked Apr 25 '14 15:04

TomOnTime


2 Answers

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.

like image 163
alecxe Avatar answered Oct 21 '22 22:10

alecxe


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...
like image 37
hpaulj Avatar answered Oct 21 '22 21:10

hpaulj