Search code examples
pythonargparse

How to override list-type arguments that have default values


If there's an ArgumentParser defined like this:

parser.add_argument("--list", type=str, nargs="+", default=["arg"])
args = parser.parse_args()

the list type arguments can have their default values overridden by setting the argument to an empty string:

python test.py --list ""

and adding logic to filter list type args for None:

for arg, value in args._get_kwargs():
    if isinstance(value, list):
        setattr(args, arg, list(filter(None, value)))

Is there anyway to do this without accessing the private method of argparse.Namespace...ideally only changing what's passed from the command-line?


Solution

  • What you want is to create a custom Action class:

    #!/usr/bin/env python3
    import argparse
    
    
    class NonEmptyListElementAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string):
            values = values or []
    
            # Get the list of values
            dest = getattr(namespace, self.dest) or []
    
            # Add to the list only those none empty values
            dest.extend(filter(None, values))
    
            # Update the namespace
            setattr(namespace, self.dest, dest)
    
    
    parser = argparse.ArgumentParser()
    parser.add_argument("--list", nargs="+", action=NonEmptyListElementAction)
    args = parser.parse_args()
    print(args)
    

    Sample run:

    $ python3 main.py --list one "" two --list "" three --list "" 
    Namespace(list=['one', 'two', 'three'])
    

    Notes

    • The namespace argument to __call__ specifies the namespace object

    • In the action class, self.dest refers to the name which you can get/set within the namespace. In this case, self.dest is "list", taken after the --list part in add_argument

    • The parser and option_string parameters are not use in this example

    • values is a list of values from command line. It is ['one', '', 'two'] in the first call, [''', 'three'] in the second call, and [''] in the last call