Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to only parse one argument group's parameters with argparse?

I'm looking to do something like this:

parser = argparse.ArgumentParser()

group1 = parser.add_argument_group('group1')
group1.add_argument('--test1', help="test1")

group2 = parser.add_argument_group('group2')
group2.add_argument('--test2', help="test2")

group1_args = group1.parse_args()
group2_args = group2.parse_args()

However, I'm getting the following error:

Traceback (most recent call last):
  File "test.py", line 19, in <module>
    group1_args = group1.parse_args()
AttributeError: '_ArgumentGroup' object has no attribute 'parse_args'

Is there a way to only get the arguments for one argument group?

like image 696
neverendingqs Avatar asked Jul 20 '15 15:07

neverendingqs


1 Answers

As your error message indicates, an ArgumentGroup is not a parser, specifically it doesn't have the parse_args method.

ArgumentParser objects and ArgumentGroup objects share a base ArgumentContainer class that gives them methods like add_argument. But an ArgumentParser has a lot of additional code. An ArgumentGroup is really just an aid in formatting the help. It does not affect parsing in any way.

To add confusion, a mutually_exclusive_group subclasses ArgumentGroup, but affects only the usage part of the help, and affects parsing by raising an error message.

If you elaborate on why you want to do this, we could come up with some alternatives that might work. For example there is a parents mechanism, that lets you insert one parser into another. Or subparsers that pass parsing control to a subparsers via 'command' arguments.


https://docs.python.org/3/library/argparse.html#parents

Defining each group in its own parent parser, would let you control both the help display, and parsing. Only problem with parents is that you have to use help=False at some level to prevent the duplication of the -h option.

You may also need to use parse_known_args so the 'group' parser does not complain about arguments that it does not recognize.


Here's a way of displaying all the args entries, grouped by argument group. I'm including the 2 default groups, optionals and positionals. It does make use of 'private' attributes of the parser. There's a bit of risk in doing so, but this isn't the kind of thing that is likely to be changed in future patches.

import argparse
parser = argparse.ArgumentParser()

group1 = parser.add_argument_group('group1')
group1.add_argument('--test1', help="test1")

group2 = parser.add_argument_group('group2')
group2.add_argument('--test2', help="test2")

args = parser.parse_args('--test1 one --test2 two'.split())

print([g.title for g in parser._action_groups])  # all group titles
print(group1._group_actions)  # arguments/actions of `group1`
print([a.dest for a in group2._group_actions]) # actions for group2

for group in parser._action_groups:
    group_dict={a.dest:getattr(args,a.dest,None) for a in group._group_actions}
    print(group.title, argparse.Namespace(**group_dict))

producing

1513:~/mypy$ python stack31519997.py 
['positional arguments', 'optional arguments', 'group1', 'group2']
[_StoreAction(option_strings=['--test1'], dest='test1', nargs=None, const=None, default=None, type=None, choices=None, help='test1', metavar=None)]
['test2']
('positional arguments', Namespace())
('optional arguments', Namespace(help=None))
('group1', Namespace(test1='one'))
('group2', Namespace(test2='two'))

If could be more convenient to work with vars(args), the dictionary version. argparse.Namespace(**adict) recreates a namespace from a dictionary.

Of coarse you make your own dest lists, ['test1'] and ['test2'].

like image 66
hpaulj Avatar answered Nov 02 '22 03:11

hpaulj