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?
Using the nargs parameter in add_argument() , you can specify the number (or arbitrary number) of inputs the argument should expect. In this example named sum.py , the --value argument takes in 3 integers and will print the sum.
argparse — parse the arguments. Using argparse is how you let the user of your program provide values for variables at runtime. It's a means of communication between the writer of a program and the user. That user might be your future self.
The store_true option automatically creates a default value of False. Likewise, store_false will default to True when the command-line argument is not present. The source for this behavior is succinct and clear: http://hg.python.org/cpython/file/2.7/Lib/argparse.py#l861.
The argparse module provides a convenient interface to handle command-line arguments. It displays the generic usage of the program, help, and errors. The parse_args() function of the ArgumentParser class parses arguments and adds value as an attribute dest of the object.
You can't use one ArgumentParser
inside another. But there is a way around. You need to extract to method code that add arguments to parser.
Then you will be able to use them to merge arguments in parser.
Also it will be easer to group arguments (related to their parsers). But you must be shore that sets of arguments names do not intersect.
Example:
foo.py:
def add_foo_params( group ):
group.add_argument('--foo', help='foo help')
if __name__ = "__main__":
parser = argparse.ArgumentParser(prog='Foo')
boo.py
def add_boo_params( group ):
group.add_argument('--boo', help='boo help')
if __name__ = "__main__":
parser = argparse.ArgumentParser(prog='Boo')
fooboo.py
from foo import add_foo_params
from boo import add_boo_params
if __name__ = "__main__":
parser = argparse.ArgumentParser(prog='FooBoo')
foo_group = parser.add_argument_group(title="foo params")
boo_group = parser.add_argument_group(title="boo params")
add_foo_params( foo_group )
add_boo_params( boo_group )
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With