1

I have the following snippet where I am using argparse with multiple subparsers

parser = argparse.ArgumentParser(description = "Setup the DB", add_help=False) parser.add_argument('action', type = str, choices=['drop','populate','print','create','print-metadata'], help = "Specify an action", default = None) subparsers = parser.add_subparsers() drop_parser = subparsers.add_parser('drop',parents=[parser]) drop_parser.add_argument('-dataset-name', required=True, type = str, help = "Dataset Name", default = None) ..... args = parser.parse_args() ..... 

When I go to run this I get the following:

python .\populatedb.py drop -dataset-name foo populatedb.py: error: invalid choice: 'foo' (choose from 'drop', 'populate', 'print', 'create', 'print-metadata') 

I am wondering where the code above is going wrong. Note that the "action" argument is a positional argument.

Thank you in advance. This is my first use of subparsers I am probably making an obvious mistake.

Thank you in advance.

Regards,

Ranga

7
  • Why are you adding an argument for the subparser? Commented Sep 12, 2016 at 22:18
  • Thanks for the quick reply. The argument is only meaningful for the action "drop" . For other options it is not meaningful hence I added it to the subparser. I left out the other subparsers for clarity. Commented Sep 12, 2016 at 22:19
  • It feels like you might need to add 'action drop'. You can run python populatedb.py -h to see the sequence of arguments you need to pass. Commented Sep 12, 2016 at 22:25
  • python .\populatedb.py -help gives the following : usage: populatedb.py {drop,populate,print,create,print-metadata} so that does not seem to be the issue. Commented Sep 12, 2016 at 22:30
  • 1
    The answer is here stackoverflow.com/questions/8250010/… Commented Sep 12, 2016 at 23:29

1 Answer 1

2

The generally accepted thing to do here is to not have an argument for the subparser -- it is it's own argument provided by argparse:

parser = argparse.ArgumentParser(description = "Setup the DB", add_help=False) subparsers = parser.add_subparsers() drop_parser = subparsers.add_parser('drop',parents=[parser]) drop_parser.add_argument('-dataset-name', required=True, type = str, help = "Dataset Name", default = None) ..... args = parser.parse_args() 

Now you don't necessarily know which parser was selected but don't worry, there's a built-in mechanism for this as well. One common use-case is having one function that should be invoked for each subparser...

parser = argparse.ArgumentParser(description = "Setup the DB", add_help=False) subparsers = parser.add_subparsers() def drop_parser_handler(args): ... drop_parser = subparsers.add_parser('drop',parents=[parser]) drop_parser.add_argument('-dataset-name', required=True, type = str, help = "Dataset Name", default = None) drop_parser.set_defaults(func=drop_parser_handler) ..... args = parser.parse_args() args.func(args) 

Of course you don't need to do anything this complex -- You could just set a constant value:

drop_parser.set_defaults(subparser_name='drop') 
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! That helped.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.