Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python - mutually exclusive arguments complains about action index

I'm trying to group arguments such that the user can do either:

python sample.py scan -a 1 -b 2
or
python sample.pt save -d /tmp -n something

here is my code:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )
    parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    group1 = root_group.add_argument_group('g1', 'scan')
    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2 = root_group.add_argument_group('g2', 'save')
    group2.add_argument('-d', help='dir')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args

as I run python sample.py --help

I'm getting an error. Can someone please tell me how to fix it?

Traceback (most recent call last):
  File "sample.py", line 18, in <module>
    args = parser.parse_args()
  File "C:\Python27\lib\argparse.py", line 1688, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1720, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1926, in _parse_known_args
    start_index = consume_optional(start_index)
  File "C:\Python27\lib\argparse.py", line 1866, in consume_optional
    take_action(action, args, option_string)
  File "C:\Python27\lib\argparse.py", line 1794, in take_action
    action(self, namespace, argument_values, option_string)
  File "C:\Python27\lib\argparse.py", line 994, in __call__
    parser.print_help()
  File "C:\Python27\lib\argparse.py", line 2313, in print_help
    self._print_message(self.format_help(), file)
  File "C:\Python27\lib\argparse.py", line 2287, in format_help
    return formatter.format_help()
  File "C:\Python27\lib\argparse.py", line 279, in format_help
    help = self._root_section.format_help()
  File "C:\Python27\lib\argparse.py", line 209, in format_help
    func(*args)
  File "C:\Python27\lib\argparse.py", line 317, in _format_usage
    action_usage = format(optionals + positionals, groups)
  File "C:\Python27\lib\argparse.py", line 388, in _format_actions_usage
    start = actions.index(group._group_actions[0])
IndexError: list index out of range

and if I add action='store_const', the error goes away and a new error occurrs asking for 4 inputs.

like image 943
max Avatar asked May 28 '15 07:05

max


People also ask

What is Store_true in Python?

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.

What is action in Argparse?

action defines how to handle command-line arguments: store it as a constant, append into a list, store a boolean value etc. There are several built-in actions available, plus it's easy to write a custom one. The one with - is an optional argument, see docs.

What is parser Add_argument in Python?

parser. add_argument('indir', type=str, help='Input dir for videos') created a positional argument. For positional arguments to a Python function, the order matters. The first value passed from the command line becomes the first positional argument. The second value passed becomes the second positional argument.

What does parse_args return?

parse_args() returns two values: options, an object containing values for all of your options— e.g. if "--file" takes a single string argument, then options. file will be the filename supplied by the user, or None if the user did not supply that option.


2 Answers

Argparse does not seem to fully support adding a group into another group. This error happens because Argparse requires root_group to have some kind of action. A workaround would be adding an argument to the group:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )

    # This is now redundant. We can remove it
    # parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    # Workaround
    root_group.add_argument('--scan', help='scan', action='store_true')
    root_group.add_argument('--save', help='save', action='store_true')

    group1 = root_group.add_argument_group('g1', 'scan')
    group2 = root_group.add_argument_group('g2', 'save')

    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2.add_argument('-d', help='dir', default='')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args 

Notice that we are using --scan and --save. To avoid using the -- prefix, you may need the help of Sub-commands. Details can be found here.

like image 156
skyline75489 Avatar answered Oct 14 '22 01:10

skyline75489


Thanks to @skyline's link above, I got it working with subparsers:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )

    scan_parser = argparse.ArgumentParser(add_help=False)
    scan_parser.add_argument('-a', '--a', help='first num', required=True)
    scan_parser.add_argument('-b', '--b', help='second num', required=True)

    save_parser = argparse.ArgumentParser(add_help=False)
    save_parser.add_argument('-d', '--d', help='directory path', required=True)
    save_parser.add_argument('-n', '--n', help='name of the file', required=True)

    sp = parser.add_subparsers()

    sp_scan = sp.add_parser('scan', parents=[scan_parser], help='scans directories')
    sp_save = sp.add_parser('save', parents=[save_parser], help='saves something')
    args = parser.parse_args()
    print args
like image 2
max Avatar answered Oct 14 '22 02:10

max