pythonpython-2.7argparse

How to add common arguments to argparse subcommands?


When using argparse, some subcommands need the same options and I'm using parents to avoid repeatedly defining them in every sub-command.

script filename: testarg.py

import argparse                                                                  

parser = argparse.ArgumentParser(add_help=False)                                 
parser.add_argument('-H', '--host', default='192.168.122.1')                     
parser.add_argument('-P', '--port', default='12345')                             
subparsers = parser.add_subparsers()                                             

# subcommand a                                                                   
parser_a = subparsers.add_parser('a', parents=[parser])                          
parser_a.add_argument('-D', '--daemon', action='store_true')                     

parser_a.add_argument('-L', '--log', default='/tmp/test.log')                    

# subcommand b                                                                   
parser_b = subparsers.add_parser('b', parents=[parser])                          
parser_b.add_argument('-D', '--daemon', action='store_true')                     

# subcommand c                                                                   
parser_c = subparsers.add_parser('c', parents=[parser])                          
args = parser.parse_args()                                                       

print args   

But when I run command:

>>>./testarg.py a
usage: testarg.py a [-h] [-H HOST] [-P PORT] [-D] [-L LOG] {a,b,c} ...
testarg.py a: error: too few arguments

expecting output:

>>>./testarg.py a
Namespace(daemon=False, host='192.168.122.1', log='/tmp/test.log', port='12345')

>>>./testarg.py b -H 127.0.0.1 -P 11111
Namespace(daemon=False, host='127.0.0.1', port='11111')

>>>./testarg.py c
Namespace(host='192.168.122.1', port='12345')

also, 

>>>./testarg.py c -H 127.0.0.1 -P 12222
Namespace(host='127.0.0.1', port='12222')

What am I missing?


Solution

  • Make a separate parent parser and pass it to subparsers

    import argparse                                                                  
    
    parent_parser = argparse.ArgumentParser(add_help=False)                                 
    parent_parser.add_argument('-H', '--host', default='192.168.122.1')                     
    parent_parser.add_argument('-P', '--port', default='12345')                             
    
    parser = argparse.ArgumentParser(add_help=False) 
    subparsers = parser.add_subparsers()                                             
    
    # subcommand a                                                                   
    parser_a = subparsers.add_parser('a', parents = [parent_parser])                          
    parser_a.add_argument('-D', '--daemon', action='store_true')                     
    
    parser_a.add_argument('-L', '--log', default='/tmp/test.log')                    
    
    # subcommand b                                                                   
    parser_b = subparsers.add_parser('b', parents = [parent_parser])                          
    parser_b.add_argument('-D', '--daemon', action='store_true')                     
    
    # subcommand c                                                                   
    parser_c = subparsers.add_parser('c', parents = [parent_parser])                          
    args = parser.parse_args()                                                       
    
    print args   
    

    This gives desired result

    $ python arg.py a
    Namespace(daemon=False, host='192.168.122.1', log='/tmp/test.log', port='12345')
    $ python arg.py b -H 127.0.0.1 -P 11111
    Namespace(daemon=False, host='127.0.0.1', port='11111')
    $ python arg.py c
    Namespace(host='192.168.122.1', port='12345')