I have an object A which contains parserA - an argparse.ArgumentParser object There is also object B which contains parserB - another argparse.ArgumentParser
Object A contains an instance of object B, however object B's arguments now need to be parsed by the parser in object A (since A is the one being called from the command line with the arguments, not B)
Is there a way to write in Python object A: parserA += B.parserB?
argparse
was developed around objects. Other than a few constants and utility functions it is all class definitions. The documentation focuses on use rather than that class structure. But it may help to understand a bit of that.
parser = argparse.ArgumentParser(...)
creates a parser
object.
arg1 = parser.add_argument(...)
creates an argparse.Action
(subclass actually) object and adds it to several parser
attributes (lists). Normally we ignore the fact that the method returns this Action object, but occasionally I find it helpful. And when I build a parser in an interactive shell I see a this action.
args = parser.parse_args()
runs another method, and returns an namespace object (class argparse.Namespace
).
The group methods and subparsers methods also create and return objects (groups, actions and/or parsers).
The ArgumentParser
method takes a parents
parameter, where the value is a list of parser objects.
With
parsera = argparse.ArgumentParser(parents=[parserb])
during the creation of parsera
, the actions and groups in parserb
are copied to parsera
. That way, parsera
will recognize all the arguments that parserb
does. I encourage you to test it.
But there are a few qualifications. The copy is by reference. That is, parsera
gets a pointer to each Action defined in parserb
. Occasionally that creates problems (I won't get into that now). And one or the other has to have add_help=False
. Normally a help action is added to a parser at creation. But if parserb
also has a help there will be conflict (a duplication) that has to be resolved.
But parents
can't be used if parsera
has been created independently of parserb
. There's no existing mechanism for adding Actions from parserb
. It might possible to make a new parser, with both as parents
parserc = argparse.ArgumentParser(parents=[parsera, parserb])
I could probably write a function that would add arguments from parserb
to parsera
, borrowing ideas from the method that implements parents
. But I'd have to know how conflicts are to be resolved.
Look at the argparse._ActionsContainer._add_container_actions
to see how arguments (Actions) are copies from a parent
to a parser
. Something that may be confusing is that each Action is part of a group
(user defined or one of the 2 default groups (seen in the help)) in addition to being in a parser
.
Another possibility is to use
[argsA, extrasA] = parserA.parse_known_args()
[argsB, extrasB] = parserB.parse_known_args() # uses the same sys.argv
# or
args = parserB.parse_args(extrasA, namespace=argsA)
With this each parser handles the arguments it knows about, and returns the rest in the extras
list.
Unless the parsers are designed for this kind of integration, there will be rough edges with this kind of integration. It may be easier to deal with those conficts with Arnial's
approach, which is to put the shared argument definitions in your own methods. Others like to put the argument parameters in some sort of database (list, dictionary, etc), and build the parser from that. You can wrap parser creation in as many layers of boilerplate as you find convenient.