Search code examples
pythoncommand-line-argumentsargparseoptparse

How can I use python command line arguments that change at run time?


I have a python program that modifies the configuration file for another program and then invokes that program. The other program uses the configuration file to define a geometry and then apply specific voltages to the different geometrical elements. I would like to be able to specify on the command line the voltages to apply to the named configuration elements. For instance the configuration file may specify an element named "base" to have a voltage 1 volt and another element named "LeftDot" to have a voltage of 1.4 volts. I would like to have a command like similar to the following:

$ python myprogram.py --config configfile1.txt --base 1.0 --LeftDot 1.4

However for another configuration file, "base" and "LeftDot" are not defined, instead this file uses "LeftNode" and "LowerGate":

$ python myprogram.py --config configfile3.txt --LeftNode 2.4 --LowerGate 0.6

In looking through argparse and optparse documentation, I don't see a way to be able to look for command line arguments that I don't know the name of until run time (when I open the configuration file, I can easily see which elements need to have voltages applied to them but only at run time.) Is there a way to tell argparse to just hand all the stuff it doesn't recognize to my own function? Thank you for your help.


Solution

  • The whole configuration is done at runtime. The examples use string constants for the names, but you are not bound to that.

    You first load the configuration, then when you have all the elements, simply loop over those and register them as arguments:

    parser = argparse.ArgumentParser(....)
    
    for element in configuration_elements:
         parser.add_argument('--' + element, type=float, ...)
    

    then parse your command line.

    Alternatively, argparse.ArgumentParser() as a partial parsing mode as well; simply call parser.parse_known_args() to parse everything that argparse does know about, it'll return a namespace object (all the options it could parse) and the remaining arguments it didn't know how to handle:

    >>> parser = argparse.ArgumentParser()
    >>> parser.add_argument('--foo')
    _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
    >>> parser.parse_known_args(['--foo', '42', '--spam', 'eggs'])
    (Namespace(foo='42'), ['--spam', 'eggs'])
    

    In the above example, .parse_known_args() did not know how to handle the '--spam' and 'eggs' arguments, so it returned those for your own code to handle. The --foo 42 argument was processed.