argparse: How to map choices to different values?

Viewed 82

When using argparse, I would like a user to select from choices, but I would like their choice to determine a more complex value (similar to how store_const works).

For example, when choosing from a smoker status of ['current', 'former', 'never'], I would like current to map to 'Current every day smoker.'

Is there an elegant way to do this?

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--smoker', choices=['current','former','never'])
print(vars(parser.parse_args()))

Normal output:

$ ./script.py --smoker current
{'smoker': 'current'}

Desired:

$ ./script.py --smoker current
{'smoker': 'Current every day smoker.'}

I thought I could do this with a lambda type argument, but argparse enforces the list of choices:

choice_dict = {'current': 'Current everyday...'}
parser.add_argument('--smoker', type=lambda x: choice_dict[x], choices=choice_dict.keys())
print(vars(parser.parse_args()))

./script.py --smoker current
usage: script.py [-h] [--smoker {current}]
script.py: error: argument --smoker: invalid choice: 'Current everyday...' (choose from 'current')
1 Answers

Though I agree with 0x5452 comment that it is better to decouple this formatting from the parser, you can use an Action to do what you want:

import argparse

CONVERSION_TABLE = {'current': 'Currently smokes',
                    'former': 'Used to smoke',
                    'never': 'Never smoke'}

class RenameOption(argparse.Action):
     def __call__(self, parser, namespace, values, option_string=None):
         setattr(namespace, self.dest, CONVERSION_TABLE[values])

parser = argparse.ArgumentParser()
parser.add_argument('--smoker', action=RenameOption, choices=CONVERSION_TABLE)
print(vars(parser.parse_args()))

The result is:

$ python test.py --smoker current
{'smoker': 'Currently smokes'}

$ python test.py --smoker no
usage: test.py [-h] [--smoker {current,former,never}]
test.py: error: argument --smoker: invalid choice: 'no' (choose from 'current', 'former', 'never')
Related