0

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

3
  • args is a dict with 2 items. What's with the len test? Commented Jun 10, 2022 at 12:20
  • @hpaulj if the string is given wrong during execution, I would like to print a message. So, thought of using the len(str) length as a criterion. It should be len(args['Chk']) Commented Jun 10, 2022 at 12:28
  • If there's a small set of allowed strings you could use the choices. The type function can also be used to test for allowable values. Commented Jun 10, 2022 at 15:10

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

@hauji Thank you.But, I dont want both -R and -C to be excecuted from command line. Either -R or -C should suffice. e.g., python main.py -R recompo should work even without -C
write your tests to ignore the variable if it has the default value (easiest if using the None default.)
0

for error handling, you can check this way:

class ArgumentParserError(Exception): pass
class ThrowingArgumentParser(argparse.ArgumentParser):
    def error(self, message):
        raise ArgumentParserError(message)

and this is maybe some help for you:

parser = ThrowingArgumentParser(description="YOUR DESCRIPTION")
parser.add_argument('func', nargs='?', choices=['C','R'], const='')

1 Comment

Why do you suggest to use a positional argument ? is it due to having atleast one optional argument during execution ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.