Question

I have a bunch of Python scripts that use common code for reading input and writing output files of different types.

These are chemical structure files. Some example file types would be .smi or .sdf.

By default, I want some of these scripts to output data in the "smi" file format, and others to output data in the "sdf" format.

Is it possible to override the default value of an argument inherited from a parent parser?

For example...

# Inherited code
filesParser = argparse.ArgumentParser(add_help=False)
filesParser.add_argument('-o', dest='outformat', default="smi")

# Script code
parser = argparse.ArgumentParser(description='inherts from filesParser', parents=[filesParser])
parser.add_argument('--foo')

# Something like...
# parser.outformat.default = "sdf"

args = parser.parse_args()

First post so hope my etiquette is OK.

Many thanks, Dave

Was it helpful?

Solution

Yes (docs):

>>> parser.parse_args([])
Namespace(foo=None, outformat='smi')
>>> parser.set_defaults(outformat='sdf')
>>> parser.parse_args([])
Namespace(foo=None, outformat='sdf')

OTHER TIPS

set_defaults is probably the easiest fix.

But I think it is worth while knowing that you can change the default of an Action directly

filesParser = argparse.ArgumentParser(add_help=False)
outaction=filesParser.add_argument('-o', dest='outformat', default="smi")
parser = argparse.ArgumentParser(description='inherts from filesParser', parents=[filesParser])
fooaction=parser.add_argument('--foo')
print fooaction.default
# None
print outaction.default
# 'smi'
outaction.default='sdf'
args=parser.parse_args()
print args
# Namespace(foo=None, outformat='sdf')

add_argument returns an Action object, which contains all the information that you specified in the arguments. Here I save (links to) those Actions in variables outaction and fooaction. outaction.default is the default value that parse_args uses.

With your inherited code it probably is awkward to save that outaction link (though it is possible to find it in 'parser._actions' list). So it makes sense to let set_defaults do the job for you.

The code for set_defaults may be instructive:

def set_defaults(self, **kwargs):
    self._defaults.update(kwargs)

    # if these defaults match any existing arguments, replace
    # the previous default on the object with the new one
    for action in self._actions:
        if action.dest in kwargs:
            action.default = kwargs[action.dest]

First it puts the new defaults in the parser._defaults dictionary, and then it conditionally modifies the action.default attribute (note the search of parser._actions). It has to do both, because when it comes time to use the defaults, the action.default value has priority over the parser._defaults value.

These details will make more sense if you run this code in an interactive shell (e.g. Ipython) and can print the action and parser objects. The usual cautions about playing with 'private' attributes apply.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top