Search code examples
pythonpython-3.xcommand-line-interfaceargparse

Argparse append action with default value only if argument doesn't appear


I'm parsing CLI arguments in my program with the argparse library. I would like to parse an argument that can repeat, with the following behaviour:

  • if the argument appears at least once, its values are stored in a list,
  • if the argument doesn't appear, the value is some default list.

I have the following code so far:

import argparse
ap = argparse.ArgumentParser(description="Change channel colours.")
ap.add_argument('-c', '--channel', action='append', default=['avx', 'fbx'])
print(ap.parse_known_args(['-c', 'iasdf', '-c', 'fdas']))
print(ap.parse_known_args())

This appropriately sets a default list, however it doesn't start with an empty list when the argument appears. In other words, the second print statement prints the correct value (the default list), but the first one prints

['avx', 'fbx', 'iasdf', 'fdas']

instead of

['iasdf', 'fdas']

Is there a way in argparse to do what I want without doing something like

if len(args.channel) > 2:
    args.channel = args.channel[2:]

after the fact?


Solution

  • There's a bug/issue discussing this behavior. I wrote several posts to that.

    https://bugs.python.org/issue16399 argparse: append action with default list adds to list instead of overriding

    For now the only change is in documentation, not in behavior.

    All defaults are placed in the namespace at the start of parsing. For ordinary actions, user values overwrite the default. But in the append case, they are just added to what's there already. It doesn't try to distinguish between values placed by the default, and previous user values.

    I think the simplest solution is to leave the default as is, and check after parsing for None or empty list (I don't recall which), and insert your default. You don't get extra points for doing all the parsing in argparse. A bit of post parsing processing is quite ok.