Search code examples
pythonconditional-statementsargparse

Handling invalid and empty arguments while using optional argparse arguments


Below is an example code that uses argparse

import os
import numpy
import argparse

def main():
    parser = argparse.ArgumentParser() 
    parser.add_argument('-C','--Chk',type=str, help='Choose arg')
    parser.add_argument('-R','--ReC',type=str, help='Choose arg')
    args = vars(parser.parse_args())
 
    if args['Chk'] == 'compo1':
        print('This is comp1')
    elif args['Chk'] == 'compo2':
        print('This is comp2')
    else:
        print('The specified comp does not exist')
    
    if args['ReC'] == 'recompo':
        print('This is second test')
    else:
        print('The specified second_T does not exist')

     
if __name__=='__main__':
    main()

The above code works fine. Since both are optional arguments, I would like to have two features:

  1. If invalid arguments are given, for -C or -R I would like to print/raise a message. I tried using raise argparse.ArgumentTypeError, see below.
if len(args) > 8 or len(args) < 3:
        raise argparse.ArgumentTypeError('Print this error message')
        return
  1. Secondly, I would like to have situations where the code should not do anything if either of -C or -R are not given. In the above code, if no arguments are given in either case, it prints The specified comp does not exist which is not ideal.

Any better way to do the above tasks ? Thanks


Solution

  • If you use choices, argparse will test for a specific set of values:

    In [44]: parser = argparse.ArgumentParser()
        ...: parser.add_argument('-C','--Chk',choices=['compo1','compo2'], help='Choose arg', default='foobar')
        ...: parser.add_argument('-R','--ReC',choices=['recompo'], help='Choose arg', default='xxx');
    

    Acceptable:

    In [45]: parser.parse_args('-C compo1 -R recompo'.split())
    Out[45]: Namespace(Chk='compo1', ReC='recompo')
    

    Defaults - I specified some strings; default default is None:

    In [46]: parser.parse_args([])
    Out[46]: Namespace(Chk='foobar', ReC='xxx')
    

    A wrong choice raises an error with usage and exit:

    In [47]: parser.parse_args('-C compo1 -R recomp1'.split())
    usage: ipykernel_launcher.py [-h] [-C {compo1,compo2}] [-R {recompo}]
    ipykernel_launcher.py: error: argument -R/--ReC: invalid choice: 'recomp1' (choose from 'recompo')
    

    A type function could be used instead if you want to limit the string lengths instead.

    Otherwise, post-parsing testing of values is best, even if the logic looks a bit messy.