3

I've created an argparse argument, which supports only 3 choices:

parser.add_argument('--param', default='ch1', choices=('ch1', 'ch2', 'ch3'), help='message')

But I have to add a new special choice ch4 which will require an additional value. I.e., my program should support such inputs:

./prog.py --param ch1
./prog.py --param ch2 # or ch3
./prog.py --param ch4='some_additional_variable'

How I can realize this (or some similar behavior)?

2
  • 1
    I don't think this comes "out of the box". You'll probably need to drop choices, add nargs=* and then do the validation yourself (either after parsing the command, or in a custom type function or argparse.Action). Commented Mar 24, 2016 at 14:51
  • what usage and help would you want to see? Commented Mar 24, 2016 at 16:50

2 Answers 2

2

You can workaround it by requiring an additional argument if ch4 param is set:

import argparse

parser = argparse.ArgumentParser(description='...')
parser.add_argument('--param', default='ch1', choices=('ch1', 'ch2', 'ch3', 'ch4'))
parser.add_argument('--setting', help="Required if param is set to ch4")

args = parser.parse_args()    
if args.param == "ch4" and not args.setting:
    parser.error("--setting is required if param is ch4")

Usage:

$ python test.py --param ch1
$ python test.py --param ch2
$ python test.py --param ch3
$ python test.py --param ch4
usage: test.py [-h] [--param {ch1,ch2,ch3,ch4}] [--setting SETTING]
test.py: error: --setting is required if param is ch
$ python test.py --param ch4 --setting "some_value"
$
Sign up to request clarification or add additional context in comments.

Comments

1

The add_argument method takes type keyword parameter. Any callable can be passed as an argument for this parameter.
Here,s a class which can be passed to the add_argument method and this may satisfy your requirement.

import argparse

class Arg(object):
    def __init__(self, value):
        self.value = value
        if '=' in value:
            self.value = value.split('=', 1)

    def __str__(self):
        return '{}=<{}>'.format(self.value[0], self.value[1]) if isinstance(self.value, list) else self.value

    def __repr__(self):
        if isinstance(self.value, list):
            return repr('{}=<value>'.format(self.value[0]))
        return '{}'.format(repr(self.value))

    def __eq__(self, value):
        return '{}'.format(repr(value)) == repr(self)

parser = argparse.ArgumentParser()
parser.add_argument('--param', default='ch1', choices=('ch1', 'ch2', 'ch3', 'ch4=<value>'), type=Arg)

args = parser.parse_args('--param ch4=123'.split())
print('choice {}, value {}'.format(args.param, repr(args.param.value)))

args = parser.parse_args([])
print('choice {}, value {}'.format(args.param, repr(args.param.value)))

args = parser.parse_args('--param ch3'.split())
print('choice {}, value {}'.format(args.param, repr(args.param.value)))

Output;

choice ch4=<123>, value ['ch4', '123']
choice ch1, value 'ch1'
choice ch3, value 'ch3'

args.param is an instance of Arg. args.param.value is either an str or a list if choice is ch4='some_value'

Comments

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.