Rectangle 27 0

Python argparse: Is there a way to specify a range in nargs?


import argparse

def required_length(nmin,nmax):
    class RequiredLength(argparse.Action):
        def __call__(self, parser, args, values, option_string=None):
            if not nmin<=len(values)<=nmax:
                msg='argument "{f}" requires between {nmin} and {nmax} arguments'.format(
                    f=self.dest,nmin=nmin,nmax=nmax)
                raise argparse.ArgumentTypeError(msg)
            setattr(args, self.dest, values)
    return RequiredLength

parser=argparse.ArgumentParser(prog='PROG')
parser.add_argument('-f', nargs='+', action=required_length(2,3))

args=parser.parse_args('-f 1 2 3'.split())
print(args.f)
# ['1', '2', '3']

try:
    args=parser.parse_args('-f 1 2 3 4'.split())
    print(args)
except argparse.ArgumentTypeError as err:
    print(err)
# argument "f" requires between 2 and 3 arguments

Ah, actually, merging your code with this answer did what I was looking for. Never mind me - unless you were thinking the same thing, in which case, check that answer out.

There is a proposed patch bugs.python.org/issue11354 to add a range nargs option, e.g. nargs=(2,3) or nargs='{2,3}' (re style notation). That approach is more powerful when other positionals have variable nargs values. Otherwise this custom action approach works fine.

Time traveler here. Great answer! However, you're subclassing argparse.Action here... what happens if I want my action to be append? How can I modify this code so that I can append multiple instances of this argument, and also get that specified range effect?

You could do this with a custom action:

Note
Rectangle 27 0

Python argparse: Is there a way to specify a range in nargs?


import argparse

def required_length(nmin,nmax):
    class RequiredLength(argparse.Action):
        def __call__(self, parser, args, values, option_string=None):
            if not nmin<=len(values)<=nmax:
                msg='argument "{f}" requires between {nmin} and {nmax} arguments'.format(
                    f=self.dest,nmin=nmin,nmax=nmax)
                raise argparse.ArgumentTypeError(msg)
            setattr(args, self.dest, values)
    return RequiredLength

parser=argparse.ArgumentParser(prog='PROG')
parser.add_argument('-f', nargs='+', action=required_length(2,3))

args=parser.parse_args('-f 1 2 3'.split())
print(args.f)
# ['1', '2', '3']

try:
    args=parser.parse_args('-f 1 2 3 4'.split())
    print(args)
except argparse.ArgumentTypeError as err:
    print(err)
# argument "f" requires between 2 and 3 arguments

Ah, actually, merging your code with this answer did what I was looking for. Never mind me - unless you were thinking the same thing, in which case, check that answer out.

There is a proposed patch bugs.python.org/issue11354 to add a range nargs option, e.g. nargs=(2,3) or nargs='{2,3}' (re style notation). That approach is more powerful when other positionals have variable nargs values. Otherwise this custom action approach works fine.

Time traveler here. Great answer! However, you're subclassing argparse.Action here... what happens if I want my action to be append? How can I modify this code so that I can append multiple instances of this argument, and also get that specified range effect?

You could do this with a custom action:

Note