can I check if a given argument is added (or "known") to argparse?

Viewed 190

Is there a way to check whether an argument with a given name has been added to an argparse instance? For instance, I'd expect something like this to be available:

argToCheck= 'my_argument'

if (argToCheck in parser.known_arguments):    # "known_arguments" isn't a thing, but it should be?
    # do some magic
else:
    # do some different magic

I'd strongly suspect that all of the added arguments are the keys to a dict buried somewhere in the argparse, possibly even one that's intentionally exposed... but I haven't been able to find them...



Background...

I have an argparse parser defined with about a dozen optional arguments:

def jumpParser():
    parser = argparse.ArgumentParser()
    parser.add_argument("-i",   "--input_file", action="store", type=str, required=True, help="input video file")
    parser.add_argument("-o",   "--output_file", action="store", type=str, required=True,  help="output video file")
    parser.add_argument("-s",   "--stamp", action="store_true",  help="enable frame stamping")
    # and so on...
    return parser

Separately, I have some code that parses an excel worksheet to call a function with a different set of arguments for each row of the XLS, with the column headers being the argument names.

Ideally, I'd like for the user to be able to have columns with headers that are NOT strictly known arguments to a specific parser, so it just skips those columns and calls the function with the arguments from that row which ARE known to a specific parser ...

2 Answers

You can access arguments that have been added to a parser with parser._actions.

[action.dest for action in parser._actions]

This will give you a list of

['help', 'input_file', 'output_file', 'stamp']

Your parser with a few tweaks. Note that add_argument returns an Action object, which can be ignored, or assigned to a variable:

In [19]: import argparse
In [20]: parser = argparse.ArgumentParser()
    ...: a1 = parser.add_argument("-i",   "--input_file", action="store", type=str, help="input video file")
    ...: a2 = parser.add_argument("-o",   "--output_file", action="store", type=str, help="output video file")
    ...: a3 = parser.add_argument("-s",   "--stamp", action="store_true",  help="enable frame stamping")
    ...: a4 = parser.add_argument("foobar")

What the repr of an Action looks like. These are the main attributes, but not all.

In [21]: a1
Out[21]: _StoreAction(option_strings=['-i', '--input_file'], dest='input_file', nargs=None, const=None, default=None, type=<class 'str'>, choices=None, help='input video file', metavar=None)
In [22]: a3
Out[22]: _StoreTrueAction(option_strings=['-s', '--stamp'], dest='stamp', nargs=0, const=True, default=False, type=None, choices=None, help='enable frame stamping', metavar=None)
In [23]: a4
Out[23]: _StoreAction(option_strings=[], dest='foobar', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)

The parser itself is an object, with methods and attributes.

In [24]: parser._actions
Out[24]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['-i', '--input_file'], dest='input_file', nargs=None, const=None, default=None, type=<class 'str'>, choices=None, help='input video file', metavar=None),
 _StoreAction(option_strings=['-o', '--output_file'], dest='output_file', nargs=None, const=None, default=None, type=<class 'str'>, choices=None, help='output video file', metavar=None),
 _StoreTrueAction(option_strings=['-s', '--stamp'], dest='stamp', nargs=0, const=True, default=False, type=None, choices=None, help='enable frame stamping', metavar=None),
 _StoreAction(option_strings=[], dest='foobar', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)]

We can test the parser with appropriate list of strings, simulating the values submitted via the commandline.

In [25]: args = parser.parse_args([])
usage: ipython3 [-h] [-i INPUT_FILE] [-o OUTPUT_FILE] [-s] foobar
ipython3: error: the following arguments are required: foobar
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2

With enough required arguments, the resulting Namespace shows all the defined arguments (unless some are SUPRESSED):

In [26]: args = parser.parse_args(['xxx'])
In [27]: args
Out[27]: Namespace(foobar='xxx', input_file=None, output_file=None, stamp=False)

We can look at this namespace object as a dictionary, e.g.

In [28]: vars(args)
Out[28]: {'input_file': None, 'output_file': None, 'stamp': False, 'foobar': 'xxx'}
In [29]: list(vars(args).keys())
Out[29]: ['input_file', 'output_file', 'stamp', 'foobar']

Those keys correspond to the argument dest attributes.

Related