Search code examples
pythonargparse

Verbose level with argparse and multiple -v options


I'd like to be able to specify different verbose level, by adding more -v options to the command line. For example:

$ myprogram.py    
$ myprogram.py -v
$ myprogram.py -vv
$ myprogram.py -v -v -v

would lead to verbose=0, verbose=1, verbose=2, and verbose=3 respectively. How can I achieve that using argparse?

Optionally, it could be great to also be able to specify it like

$ myprogram -v 2

Solution

  • You could do this with nargs='?' (to accept 0 or 1 arguments after the -v flag) and a custom action (to process the 0 or 1 arguments):

    import sys
    import argparse
    
    class VAction(argparse.Action):
        def __init__(self, option_strings, dest, nargs=None, const=None, 
                     default=None, type=None, choices=None, required=False, 
                     help=None, metavar=None):
            super(VAction, self).__init__(option_strings, dest, nargs, const, 
                                          default, type, choices, required, 
                                          help, metavar)
            self.values = 0
        def __call__(self, parser, args, values, option_string=None):
            # print('values: {v!r}'.format(v=values))
            if values is None:
                self.values += 1
            else:
                try:
                    self.values = int(values)
                except ValueError:
                    self.values = values.count('v')+1
            setattr(args, self.dest, self.values)
    
    # test from the command line
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
    args = parser.parse_args()
    print('{} --> {}'.format(sys.argv[1:], args))
    
    print('-'*80)
    
    for test in ['-v', '-v -v', '-v -v -v', '-vv', '-vvv', '-v 2']:
        parser = argparse.ArgumentParser()
        parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
        args=parser.parse_args([test])
        print('{:10} --> {}'.format(test, args))
    

    Running script.py -v -v from the command line yields

    ['-v', '-v'] --> Namespace(verbose=2)
    --------------------------------------------------------------------------------
    -v         --> Namespace(verbose=1)
    -v -v      --> Namespace(verbose=2)
    -v -v -v   --> Namespace(verbose=3)
    -vv        --> Namespace(verbose=2)
    -vvv       --> Namespace(verbose=3)
    -v 2       --> Namespace(verbose=2)
    

    Uncomment the print statement to see better what the VAction is doing.