Tuesday, June 27, 2017

Python argparse with defaults -- in-script and importable

I've tried using argparse (and optparse before that) and have had trouble finding a workflow that made me happy. This one is pretty close. It allows you to make defaults for when you call a script on the command line and makes those same defaults available if you import the module. It works like this:
  1. Make a dictionary with the defaults you want.
  2. In the function you write that parses the arguments, use the dictionary values as the defaults.
  3. Merge the defaults dictionary and the arguments dictionary together.
  4. Return the merged dictionary.
The Gist version is available here, or you can see it below, too.

 #######################################

#!/usr/bin/python3
'''
> python3 args_example.py -h
usage: args_example.py [-h] [-f FIRST_OPTION] [-s SECOND_OPTION]
                       mandatory_argument

Example argument parser with default values.

positional arguments:
  mandatory_argument    Not everything can have a default value. This is a
                        mandatory argument.

optional arguments:
  -h, --help            show this help message and exit
  -f FIRST_OPTION, --first_option FIRST_OPTION
                        This is the first option. Default:
                        first_default_value.
  -s SECOND_OPTION, --second_option SECOND_OPTION
                        This is the second option. (Default:
                        second_default_value)
  -t THIRD_OPTION, --third_option THIRD_OPTION
                        This is the third option. (Default:
                        third_default_value)

> python3 args_example.py -f "non-default first value" --second_option 'non-default second value' "this is mandatory"                                                      
{'first_option': 'non-default first value',
 'mandatory_argument': 'this is mandatory',
 'second_option': 'non-default second value',
 'third_option': 'third_default_value'}

Of course, https://pymotw.com/2/argparse/ is still excellent.
'''


import argparse
import pprint


default_settings = {'first_option': 'first_default_value',
                    'second_option': 'second_default_value',
                    'third_option': 'third_default_value'}


def get_args(settings=default_settings):
    '''Reads from sys.stdin. Use stdin to get new options, and return options
    merged with the default options. Settings is a dictionary. We'll have an
    argument (no, you came here for an argument), set two options, and default
    one.
    '''

    parser = argparse.ArgumentParser(description='Example argument parser with default values.')
    parser.add_argument('mandatory_argument', help='Not everything can have a default value. This is a mandatory argument.')
    parser.add_argument('-f', '--first_option', help='This is the first option. Default: %(default)s.',
                        default=settings['first_option'])
    parser.add_argument('-s', '--second_option', help='This is the second option. (Default: %(default)s)',
                        default=settings['second_option'])
    parser.add_argument('-t', '--third_option', help='This is the third option. (Default: %(default)s)',
                        default=settings['third_option'])
    args = parser.parse_args()
    args_settings = vars(args) # everything is easier with a dictionary
 
    #python3.5+
    merged_settings_3 = {**settings, **args_settings}

    #python2
    merged_settings_2 = default_settings.copy()
    merged_settings_2.update(args_settings)

    merged_settings_brute_force = '''
    if args.first_option:
        settings['first_option'] = args.first_option
    if args.second_option:
        settings['second_option'] = args.second_option
    if args.third_option:
        settings['third_option'] = args.third_option
    settings['mandatory_argument'] = args.mandatory_argument
    return merged_settings_brute_force
        '''

    return merged_settings_3


def main():
    settings = get_args()
    pprint.pprint(settings)


if __name__ == '__main__':
    main()

No comments:

Post a Comment