Search code examples
pythonpython-3.xpython-3.7

argparse type validation for nargs input


I'm using python 3.74 and I'm trying to use the argparse module to read a pair of numbers into the variable nums. I would like to check if certain conditions hold between the two numbers and then sort them.

I have the code below.

import argparse

def f(x):
   assert x[0]!=x[1],"err"
   return sorted([int(y) for y in x])

parser = argparse.ArgumentParser()
parser.add_argument("--nums", required=True, type=f,nargs=2)
args = parser.parse_args()  

I want the snippet above to return [1, 2] when the input is 2 1. I get an IndexError instead.

This led me to investigate with the code below:

parser = argparse.ArgumentParser()
parser.add_argument("--nums", required=True, type=lambda x:x*2 ,nargs=2)
args = parser.parse_args()

now the output for 2 1 is ['22', '11'] which leads me to believe that type is applied te each of the values separately. Is there any way to perform type validation on --nums as a whole? I'd preferably like to do it within add_argument.


Solution

  • As the documentation states

    type= can take any callable that takes a single string argument and returns the converted value

    And we can confirm this by looking at the ArgParse implementation, nargs arguments are evaluated individually. So your f function is being called for each argument.

    If you really want it to be done as part of the type checking, you could require a string input of 1,2 and parse that yourself like so:

    def f(x):
        x = x.split(',')
        assert x[0]!=x[1],'err'
        return sorted([int(y) for y in x])
    

    Where an input of 1,2 results in [1, 2]

    But that defeats the purpose of argparse, so you're better off simply calling your validator after the arguments have been parsed, the experience for the end-user is no different.

    parser.add_argument("--nums", required=True, type=int, nargs=2)
    args = parser.parse_args()
    print(f(args.nums))
    

    An input of 2 1 returns [1, 2]