argparse identify which subparser was used
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
argparse subparsers let one command-line program expose multiple commands, such as tool build and tool test. Once you add subparsers, you usually need to know which one the user invoked so you can dispatch to the right handler. The cleanest solutions are to store the subcommand name with dest or to attach a handler function to each subparser with set_defaults().
Store the Subcommand Name with dest
The direct way to identify which subparser was used is to give add_subparsers() a destination attribute:
If the user runs mytool build, then args.command becomes "build". If the user runs mytool test, it becomes "test".
This is useful when you want to route execution with an if or match statement.
Dispatch Cleanly with set_defaults()
A more scalable pattern is to attach a handler function to each subparser:
This avoids a growing chain of if args.command == ... statements. Each subparser carries the code path it should invoke.
Use Both Patterns Together When Helpful
You do not have to choose only one pattern. It is often useful to keep both the command name and the handler:
This is useful for logging, metrics, or debugging while still keeping dispatch logic clean.
Handle the Missing-Subcommand Case Properly
In modern Python, use required=True on add_subparsers() when a subcommand is mandatory. Without it, args.command may be None, and args.func may not exist.
If you need compatibility with older behavior, add a guard:
That makes the failure mode explicit instead of crashing with an attribute error.
Nested Subparsers Follow the Same Idea
For multi-level CLIs, the same approach still works. Each level can store its chosen name with dest, and the leaf subparser can set the final handler.
The same principles apply. The command path is just deeper.
Which Pattern Should You Prefer
If the CLI is tiny, dest plus a simple conditional is fine. If the CLI is growing or has many subcommands, set_defaults(func=...) usually ages better.
A good rule of thumb is:
- use
destwhen you mainly need the subcommand name - use
set_defaults()when you mainly need command dispatch - combine both when you want clean dispatch and easy observability
Common Pitfalls
One common mistake is forgetting dest and then wondering why there is no args.command attribute. Without dest, the chosen subparser name is not stored automatically.
Another mistake is calling args.func(args) without ensuring a subcommand was actually selected. If no handler was attached, the program fails with an attribute error.
Developers also sometimes set defaults on the parent parser instead of on the individual subparsers, which can make dispatch behavior confusing.
Finally, if you are building a nested CLI, keep the names distinct. Reusing vague destination names across levels can make the parsed namespace harder to read.
Summary
- Use
add_subparsers(dest="command")to store the chosen subcommand name. - Use
set_defaults(func=handler)on each subparser for clean dispatch. - '
required=Truehelps enforce that a subcommand is actually provided.' - You can combine
destandset_defaults()when you want both command names and handlers. - The same patterns work for nested subparsers too.

