Argparse notes

From raju

only allow some values for a positional argument

tags | valid values

Example 1:

        parser.add_argument("--model", required=True, choices=['slow', 'fast'], help='model specification.')
    

Example 2:

        parser.add_argument("access", action='store',
            choices=['allow', 'deny'], help='type of access')
    

Ref:-

create parser

    import argparse
    
    def create_parser():
        parser = argparse.ArgumentParser(description='Get list of elements')
        parser.add_argument('elements', nargs='+', help="list of elements")
        return parser
    
    if __name__ == '__main__':
        parser = create_parser()
        args = parser.parse_args()
    
  • http://dustinrcollins.com/testing-python-command-line-apps - shows how to test command line python apps. Notice how he breaks up the code. The function create_parser() only initializes the parser and adds arguments. The actual parsing is done after calling the create_parser() function. This way we can use create_parser() in unit tests and modify it as needed.

useful links

pass list

You can either use the nargs option or the 'append' setting of the action option (depending on how you want the user interface to behave).

nargs='+' takes 1 or more arguments, nargs='*' takes zero or more.

    UI with nargs: -l val1 val2 val3
    parser.add_argument('-l', '--my-list', nargs='+', help='Required list of items', required=True)
    
    UI with action='append': -l val1 -l val2 -l val3
    parser.add_argument('-l', '--my-list', action='append', help='Required list of items', required=True)
    
    UI with mandatory args: val1 val2 val3
    # 'required' option should not used for mandatory arguments.
    parser.add_argument('elements', nargs='+', help='List of elements')
    


All options are converted to strings.


Sample code:- https://github.com/KamarajuKusumanchi/sampleusage/blob/master/python/pass_list.py

Ref:- https://stackoverflow.com/questions/15753701/how-can-i-pass-a-list-as-a-command-line-argument-with-argparse

Introduction

For parsing command line arguments in Python use argparse. Do not use optparse (which is deprecated) or getopt (which involves writing more code).

parse and validate

tags| fail if an option's value is not specified

    def parse_arguments(args):
        import argparse
        parser = argparse.ArgumentParser(
            description='Get input'
            )
        parser.add_argument(
            "--foo", action='store',
            dest='foo',
            help='User must specify a value for foo on the command line.')
        parser.add_argument(
            "--debug", action='store_true',
            default=False, dest='debug',
            help='show debug output. Default is false.')
    
        res = parser.parse_args(args)
        if res.debug:
            print(res)
        return res
    
    def validate_arguments(args):
        foo = args.foo
        if (foo is None):
            print("Error: foo is not specified. Please specify one.")
            raise()
    
    if __name__ == "__main__":
        args = parse_arguments(sys.argv[1:])
        validate_arguments(args)
    

Sample usage of argparse

    import argparse
    import textwrap  # for dedent

    parser = argparse.ArgumentParser(
        description='Explain what the script does')

    # Description spanning across multiple lines
    parser = argparse.ArgumentParser(
        description='''Utility script that tells why a given set of packages
        are installed.''')

    # preformatted description and epilog
    parser = argparse.ArgumentParser(
        description='My super duper space probe',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent('''\
        Features:
        * Ability to orbit Jupiter
        * Ability to scratch Sun
        '''))


    # mandatory positional argument
    parser.add_argument(
        "pattern", action="store",
        help="pattern to search for")

    # optional positional argument
    parser.add_argument(
        "dir", nargs='?',
        default=os.getcwd(),
        help="directory")

    # optional argument that has a default value
    parser.add_argument(
        "--out_dir", default='~/scratch',
        help="output directory name")

    parser.add_argument("--dry", action="store_true",
        default=False, dest="dry",
        help="perform a trial run with no actual changes")
    parser.add_argument("--debug", action="store_true",
        default=False, dest="debug",
        help="show debug output")

    args = parser.parse_args()

pass dictionary

    import json
    parser.add_argument('-d', '--my_dict', type=json.loads)
    args = parse.parse_args()
    
    mydict = args.my_dict  # Will return a dictionary
    

Call the script as

    <script> --my_dict '{"value1":"key1"}'
    

Ref:- http://stackoverflow.com/questions/18608812/accepting-a-dictionary-as-an-argument-with-argparse-and-python

--feature and --no-feature

all positional arguments into a list

        parser.add_argument(
            'input_files', nargs='*',
            action='store',
            help='list of input files'
    


show default values in the help page

There are two ways to achieve this

Specify the formatter_class parameter when initializing the parser.

        parser = argparse.ArgumentParser(
            description='''Do something.
            ''',
            formatter_class=argparse.ArgumentDefaultsHelpFormatter
        )
    

Ref:- https://docs.python.org/3/library/argparse.html#argparse.ArgumentDefaultsHelpFormatter

or add '%(default)' in the help string and include the variable 'type' in the formatting string -- e.g. '%(default)s' for a string, or '%(default)d' for a digit.

        parser.add_argument(
            '--out-dir',
            default='C:\Temp\output',
            help='Output directory. Default = %(default)s'
        )
    

Ref:- https://stackoverflow.com/a/18507871/6305733

raise incompatible argument error

    def validate_options(args):
        if any(v is None for v in [args.old_date, args.new_date]) and \
                any(v is None for v in [args.old_dir, args.new_dir]):
            raise ValueError('Incompatible arguments. Either specify --old-date '
                             'and --new_date or --old-dir and --new-dir.\n'
                             'Specified values are:\n {}'.format(args))
    

check later

convert input from string to integer

   parser.add_argument(
       '--daily-history', dest='daily_history',
       default=30, type=int,
       help='number of daily output files to be preserved. Default = 30'
   )