217

I think this must be easy but I do not get it.

Assume I have the following arparse parser:

import argparse

parser = argparse.ArgumentParser( version='pyargparsetest 1.0' )
subparsers = parser.add_subparsers(help='commands')

# all
all_parser = subparsers.add_parser('all', help='process all apps')

# app
app_parser = subparsers.add_parser('app', help='process a single app')
app_parser.add_argument('appname', action='store', help='name of app to process')

How can I identify, which subparser was used? calling:

print parser.parse_args(["all"])

gives me an empty namespace:

Namespace()
phooji
  • 10,086
  • 2
  • 38
  • 45
user1062880
  • 2,181
  • 2
  • 13
  • 5

2 Answers2

386

A simpler solution is to add dest to the add_subparsers call. This is buried a bit further down in the documentation:

[...] If it is necessary to check the name of the subparser that was invoked, the dest keyword argument to the add_subparsers() call will work

In your example replace:

subparsers = parser.add_subparsers(help='commands')

with:

subparsers = parser.add_subparsers(help='commands', dest='command')

Now if you run:

print parser.parse_args(["all"])

you will get

Namespace(command='all')
quornian
  • 9,495
  • 6
  • 30
  • 27
  • 4
    This seems like the correct way, as it works like the `dest` param on any other argument (only it defaults to `None`, rather than being pulled from the `--longopt` value). Using `set_defaults` seems inappropriate for this (but useful for other things) – dbr Jun 06 '12 at 12:01
  • 1
    This is the correct answer! Would be nice to have an example how to test the "command" value. – Eugene Sajine Feb 26 '14 at 19:16
  • BTW if there is function in the same class by the name of the command one could do: "getattr(self, args.command)()" to execute it by name! – Eugene Sajine Feb 26 '14 at 19:32
  • Can I somehow get the subparser itself instead of just its name ? – Mr_and_Mrs_D Jun 07 '17 at 15:19
  • Note, there might be a non-obvious problem: if you execute `.add_argument('--command')`, i.e. add an argument whose name matches the `dest` one, then value of that argument *(if passed)* will overwrite the name of the parser. I think such problematic configuration should really be detected by argparse , but unfortunately it isn't. – Hi-Angel Nov 30 '20 at 12:35
  • The problem with this answer is that the `dest` variable will contain the alias used (when aliases are in play), not the command name itself. For such cases, `set_defaults` can help. – ypnos Jul 23 '21 at 11:58
94

Edit: Please see quornian's answer to this question, which is better than mine and should be the accepted answer.

According to the argparse documentation the result of parser.parse_args(...) will "only contain attributes for the main parser and the sub parser that was selected". Unfortunately this may not be enough information to determine which sub parser was used. The documentation recommends using the set_defaults(...) method on the sub parser to solve this problem.

For example, I've added calls to set_defaults() to your code:

import argparse

parser = argparse.ArgumentParser( version='pyargparsetest 1.0' )
subparsers = parser.add_subparsers(help='commands')

# all
all_parser = subparsers.add_parser('all', help='process all apps')
all_parser.set_defaults(which='all')

# app
app_parser = subparsers.add_parser('app', help='process a single app')
app_parser.add_argument('appname', action='store', help='name of app to process')
app_parser.set_defaults(which='app')

Now if you run

print parser.parse_args(["all"])

The result is

Namespace(which='all')

Check out the add_subparsers() documentation for more information and another example.

David C
  • 7,204
  • 5
  • 46
  • 65
srgerg
  • 18,719
  • 4
  • 57
  • 39
  • 11
    `set_defaults` is useful, like in the docs' example where it uses it to bind a sub-command to a function.. but `add_parser(dest='which')` appears to be the "correct" way to do this, as it doesn't require repeating the subcommand name – dbr Jun 06 '12 at 12:02
  • 1
    @dbr Yep, you're right. Quornian's answer should be the accepted one. – srgerg Jun 07 '12 at 00:23
  • 2
    @dbr, should be `add_subparsers(dest='which')` – smac89 Sep 15 '17 at 01:54
  • This answer is actually very helpful as the solution provided by @quornian has a flaw when using aliases. The alias will be in the dest variable, not the command name. See also https://stackoverflow.com/questions/59493715/resolve-argparse-alias-back-to-the-original-command – ypnos Jul 23 '21 at 11:56