argparse Subparsers Not Required by Default (tested)
add_subparsers() looks like it defines a mandatory choice — run, build, whatever your sub-commands are. We measured what happens when a user runs the program with none of them, and argparse doesn't consider that an error.
1. parse_args([]) succeeds with no sub-command chosen
import argparse
p = argparse.ArgumentParser()
sub = p.add_subparsers(dest="cmd")
run_parser = sub.add_parser("run")
run_parser.add_argument("--x")
args = p.parse_args([])
print(args)
Namespace(cmd=None)
Measured: running the program with zero arguments doesn't raise a usage error. args.cmd is just None. Nothing in the run sub-parser ran, so none of its arguments — including --x — were ever added to the namespace at all.
2. Accessing the missing sub-command's argument fails later, not here
try:
print(args.x)
except AttributeError as e:
print("AttributeError:", e)
AttributeError: 'Namespace' object has no attribute 'x'
Measured: the failure isn't at parse_args(), where the actual problem (no sub-command given) happened — it's an AttributeError wherever the code first reads args.x, which could be dozens of lines and several function calls away. There's no usage message pointing back to the missing sub-command, just a generic missing-attribute crash at an unrelated line.
3. Fix: pass required=True to add_subparsers()
p2 = argparse.ArgumentParser()
sub2 = p2.add_subparsers(dest="cmd", required=True)
run_parser2 = sub2.add_parser("run")
run_parser2.add_argument("--x")
try:
p2.parse_args([])
except SystemExit as e:
print("SystemExit code:", e.code)
usage: prog [-h] {run} ...
prog: error: the following arguments are required: cmd
SystemExit code: 2
Measured: adding required=True (available since Python 3.7) makes parse_args([]) print a proper usage error and exit with code 2 — the standard argparse failure mode for missing required arguments — instead of silently returning a namespace that's missing everything the chosen sub-command would have added. This is opt-in, not the default, so every add_subparsers() call that's meant to be mandatory needs it explicitly.
Frequently asked questions
Are argparse sub-commands required by default?
No — we measured parse_args([]) succeeding with no sub-command chosen and dest set to None, unless add_subparsers() is called with required=True.
Why do I get AttributeError on an argparse Namespace instead of a usage error?
We confirmed that when no sub-command is chosen and subparsers aren't required, none of that sub-command's arguments are added to the Namespace at all, so accessing them later raises AttributeError far from the real cause.
How do I make an argparse sub-command mandatory?
We verified passing required=True to add_subparsers() (available since Python 3.7) makes parse_args() print a usage error and exit with status 2 when no sub-command is given.
What does add_subparsers(dest='cmd') do if no sub-command is required?
We measured args.cmd being set to None when the user gives no sub-command and required isn't set, rather than argparse raising any error.
Does Python's argparse treat missing sub-commands as an error automatically?
In our test, no — argparse only enforces a sub-command choice if you explicitly set required=True on add_subparsers(); without it, an empty command line parses successfully.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in argparse module: built a parser with add_subparsers() and a sub-command-only argument, then called parse_args([]) with no sub-command given, both with and without required=True. PlainHeaders is our extension; Python's argparse module is built in.