How to find out if argparse argument has been actually specified on command line?

You can use custom action to tell if an arg value was defaulted or set on command line:

import argparse

class FooAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)
        setattr(namespace, self.dest+'_nondefault', True)

parser = argparse.ArgumentParser()
parser.add_argument('--test0', default='meaningful_default', action=FooAction)
parser.add_argument('--test1', default='meaningful_default', action=FooAction)

args = parser.parse_args('--test0 2'.split())

if hasattr(args, 'test0_nondefault'):
    print('argument test0 set on command line')
else:
    print('default value of test0 is used')

if hasattr(args, 'test1_nondefault'):
    print('argument test1 set on command line')
else:
    print('default value of test1 is used')

You can use combinations of "const" and "default" to emulate what you want. "nargs" has to be '?' in this case. For example:

args_group.add_argument('--abc',
                         metavar='',
                         nargs='?',
                         action='store',
                         const='github.com',
                         default='',
                         help='blabla [ default: %(const)s ]')

Then abc's value will be as follows given different command line arguments.

abc not in command line:

abc =

--abc:

abc = github.com

--abc stackoverflow.com:

abc = stackoverflow.com

So you will know abc doesn't appear in command line when it's blank, for example:

if not args.abc:
    # to something

If you prefer to use argparse and to be able to specify default values, there is a simple solution using two parsers.

I. Define your main parser and parse all your arguments with proper defaults:

parser = argparse.ArgumentParser()
parser.add_argument('--test1', default='meaningful_default1')
parser.add_argument('--test2', default='meaningful_default2')
...
args, unparsed = parser.parse_known_args()

II. Define an aux parser with argument_default=argparse.SUPPRESS to exclude unspecified arguments. Add all the arguments from the main parser but without any defaults:

aux_parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
for arg in vars(args): aux_parser.add_argument('--'+arg)
cli_args, _ = aux_parser.parse_known_args()

This is not an extremely elegant solution, but works well with argparse and all its benefits.


The parser maintains a seen_actions set object while parsing (in the _parse_known_args method). At the end of parsing it checks this set against the required arguments (ones with required=True), and may issue a error. A variation is also used with mutually exclusive groups.

But this variable is not available outside of that function. So short of some sort of 'hook' that lets you apply your own tests within the parse_args action, your best option is to test defaults. Or you can look at sys.argv[1:].

The default default is None. That is nice for this purpose because your user cannot give this value. That is, there's no string that converts to None (at least not in any of the normal type methods).

parser.add_argument('--foo') # default=None
...
if args.foo is None:
    # clearly foo has not been specified.
    args.foo = 'the real default'
else:
    # foo was specified
    pass