Python argparse Cheat Sheet
1 · The lesson
readWhen you run a script as python resize.py cat.png --size 400, the words after the script name are its command-line arguments. The argparse module reads those words, turns them into values of the right type, and writes the help text and error messages for you. For the full tutorial, see CLI tools.
In a real script you call p.parse_args() with nothing in the brackets, and it reads the words that were typed. On this page we pass a list instead, such as p.parse_args(["cat.png"]), so you can try every example in the browser without a terminal.
1. The skeleton
A full script looks like this. Save it as resize.py and run python resize.py cat.png --size 400 on your computer:
import argparse def main(): p = argparse.ArgumentParser(description="Resize images.") p.add_argument("path") p.add_argument("--size", type=int, default=800) args = p.parse_args() # reads the words typed after the script name print(args.path, args.size) if __name__ == "__main__": main()
The same parser, tried with a list:
import argparse from pathlib import Path p = argparse.ArgumentParser(prog="tool", description="Resize images.") p.add_argument("path") # a positional argument: required p.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out p.add_argument("--size", type=int, default=800) # an option: its name starts with -- args = p.parse_args(["cat.png"]) print(vars(args)) # {'path': 'cat.png', 'out': 'out.png', 'size': 800} print(args.path) # cat.png print(p.parse_args(["a", "--size", "9"]).size) # 9 print(p.parse_args(["a", "--size=9"]).size) # 9
A positional argument is filled in by its place in the list. An option has a name that starts with -- (or - for a short name), and you may leave it out. Each value becomes an attribute of args, and vars(args) shows them all as a dict. type=int turned the text "9" into the number 9.
2. On/off flags
A flag is an option that takes no value: it is either there or not.
from argparse import BooleanOptionalAction p = argparse.ArgumentParser(prog="tool") p.add_argument("-v", "--verbose", action="store_true") p.add_argument("--dry-run", action="store_true") p.add_argument("--no-cache", dest="cache", action="store_false") p.add_argument("--color", default=True, action=BooleanOptionalAction) print(p.parse_args(["-v"]).verbose) # True print(p.parse_args([]).verbose) # False print(p.parse_args(["--dry-run"]).dry_run) # True print(p.parse_args([]).cache) # True print(p.parse_args(["--no-color"]).color) # False
setup added so this can run · re-runs 1 earlier block on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
With store_true, the value is False unless the flag is given. -v and --verbose both work. A - in the name becomes _ in the attribute, so --dry-run is args.dry_run. store_false is the opposite: the value is True unless the flag is given. dest= picks the attribute name. BooleanOptionalAction makes both --color and --no-color.
3. Values
p = argparse.ArgumentParser(prog="tool") p.add_argument("--ratio", type=float) p.add_argument("--out", type=Path) p.add_argument("--fmt", default="json", choices=["json", "csv"]) print(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5 print(p.parse_args([]).ratio) # None print(p.parse_args(["--out", "res"]).out.name) # res print(p.parse_args(["--fmt", "csv"]).fmt) # csv
setup added so this can run · re-runs 2 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
If you leave out an option that has no default, its value is None. type= accepts any function that takes one string, such as int, float or Path. With choices=, any other value is refused. required=True makes an option that must be given.
When the input is wrong, argparse prints a short usage line and an error, then stops the program with exit code 2. It does this by raising SystemExit. Here we catch SystemExit to show the exit code:
try: p.parse_args(["--fmt", "xml"]) except SystemExit as e: print("exit code", e.code) # exit code 2
setup added so this can run · re-runs 3 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) p = _AutoMock('p') argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
The error message itself goes to stderr (the error output of the program): tool: error: argument --fmt: invalid choice: 'xml' (choose from json, csv).
4. Several values
nargs says how many values an argument takes:
nargs | Means | You get |
|---|---|---|
| (not given) | exactly one | one value |
2 | exactly 2 | a list of 2 |
"?" | zero or one | one value, or the default |
"*" | zero or more | a list, maybe empty |
"+" | one or more | a list with at least one item |
p = argparse.ArgumentParser(prog="tool") p.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point p.add_argument("--tag", action="append") # repeat the flag to collect values p.add_argument("-q", action="count", default=0) # counts how often the flag appears p.add_argument("files", nargs="+") # one or more values, as a list a = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"]) print(a.files) # ['a.txt', 'b.txt'] print(a.p) # [8, 6] print(a.tag) # ['a', 'b'] print(a.q) # 3
setup added so this can run · re-runs 3 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
5. Check a value yourself
Write a function for type=. If the text is not acceptable, raise ArgumentTypeError with a clear message, and argparse shows it as a normal error.
from argparse import ArgumentTypeError def positive(text): n = int(text) if n > 0: return n raise ArgumentTypeError("need > 0") p = argparse.ArgumentParser(prog="tool") p.add_argument("--jobs", type=positive) print(p.parse_args(["--jobs", "4"]).jobs) # 4
setup added so this can run · re-runs 4 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
tool --jobs 0 would stop with error: argument --jobs: need > 0.
6. Subcommands (git style)
Some tools have commands inside them, like git add and git commit. Each command has its own arguments.
p = argparse.ArgumentParser(prog="tool") sub = p.add_subparsers(dest="cmd", required=True) # dest= stores which command was chosen add = sub.add_parser("add", help="add an item") add.add_argument("item") rm = sub.add_parser("rm", help="remove an item") rm.add_argument("item") rm.add_argument("--force", action="store_true") def do_add(args): print("adding", args.item) add.set_defaults(func=do_add) a = p.parse_args(["rm", "x", "--force"]) print(a.cmd, a.item, a.force) # rm x True a = p.parse_args(["add", "milk"]) a.func(a) # adding milk
setup added so this can run · re-runs 5 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction from argparse import ArgumentTypeError except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', 'from argparse import ArgumentTypeError\n\ndef positive(text):\n n = int(text)\n if n > 0:\n return n\n raise ArgumentTypeError("need > 0")\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("--jobs", type=positive)\nprint(p.parse_args(["--jobs", "4"]).jobs) # 4', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
set_defaults(func=...) stores a function with each command, so args.func(args) runs the function of the chosen command. You do not need a chain of if statements.
7. Help and usage
p = argparse.ArgumentParser(prog="tool", epilog="Example: tool --json") g = p.add_mutually_exclusive_group() # one or the other, never both g.add_argument("--json", action="store_true") g.add_argument("--csv", action="store_true") print(p.format_usage(), end="") # usage: tool [-h] [--json | --csv] p.add_argument("--out", metavar="FILE", help="where to save") p.add_argument("--version", action="version", version="1.0") print(p.parse_known_args(["--json", "--x"])[1]) # ['--x']
setup added so this can run · re-runs 6 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction from argparse import ArgumentTypeError except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', 'from argparse import ArgumentTypeError\n\ndef positive(text):\n n = int(text)\n if n > 0:\n return n\n raise ArgumentTypeError("need > 0")\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("--jobs", type=positive)\nprint(p.parse_args(["--jobs", "4"]).jobs) # 4', 'p = argparse.ArgumentParser(prog="tool")\nsub = p.add_subparsers(dest="cmd", required=True) # dest= stores which command was chosen\n\nadd = sub.add_parser("add", help="add an item")\nadd.add_argument("item")\n\nrm = sub.add_parser("rm", help="remove an item")\nrm.add_argument("item")\nrm.add_argument("--force", action="store_true")\n\ndef do_add(args):\n print("adding", args.item)\n\nadd.set_defaults(func=do_add)\n\na = p.parse_args(["rm", "x", "--force"])\nprint(a.cmd, a.item, a.force) # rm x True\n\na = p.parse_args(["add", "milk"])\na.func(a) # adding milk', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
The usage line is written for you from the arguments. help= is the text shown next to the argument in -h, and metavar= is the name shown for its value. -h and --help are added for you: they print the help and stop. --version prints 1.0 and stops. epilog= is text at the end of the help. parse_known_args() returns the words it does not know, instead of stopping with an error.
Common mistakes
Forgetting type=int. Every value starts as text:
p = argparse.ArgumentParser(prog="tool") p.add_argument("--count") print(repr(p.parse_args(["--count", "3"]).count)) # '3'
setup added so this can run · re-runs 7 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction from argparse import ArgumentTypeError except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', 'from argparse import ArgumentTypeError\n\ndef positive(text):\n n = int(text)\n if n > 0:\n return n\n raise ArgumentTypeError("need > 0")\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("--jobs", type=positive)\nprint(p.parse_args(["--jobs", "4"]).jobs) # 4', 'p = argparse.ArgumentParser(prog="tool")\nsub = p.add_subparsers(dest="cmd", required=True) # dest= stores which command was chosen\n\nadd = sub.add_parser("add", help="add an item")\nadd.add_argument("item")\n\nrm = sub.add_parser("rm", help="remove an item")\nrm.add_argument("item")\nrm.add_argument("--force", action="store_true")\n\ndef do_add(args):\n print("adding", args.item)\n\nadd.set_defaults(func=do_add)\n\na = p.parse_args(["rm", "x", "--force"])\nprint(a.cmd, a.item, a.force) # rm x True\n\na = p.parse_args(["add", "milk"])\na.func(a) # adding milk', 'p = argparse.ArgumentParser(prog="tool", epilog="Example: tool --json")\ng = p.add_mutually_exclusive_group() # one or the other, never both\ng.add_argument("--json", action="store_true")\ng.add_argument("--csv", action="store_true")\nprint(p.format_usage(), end="") # usage: tool [-h] [--json | --csv]\n\np.add_argument("--out", metavar="FILE", help="where to save")\np.add_argument("--version", action="version", version="1.0")\nprint(p.parse_known_args(["--json", "--x"])[1]) # [\'--x\']', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Fix: p.add_argument("--count", type=int).
type=bool. bool("False") is True, because any non-empty string counts as true:
p.add_argument("--debug", type=bool) print(p.parse_args(["--debug", "False"]).debug) # True
setup added so this can run · re-runs 9 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) p = _AutoMock('p') argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction from argparse import ArgumentTypeError except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'try:\n p.parse_args(["--fmt", "xml"])\nexcept SystemExit as e:\n print("exit code", e.code) # exit code 2', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', 'from argparse import ArgumentTypeError\n\ndef positive(text):\n n = int(text)\n if n > 0:\n return n\n raise ArgumentTypeError("need > 0")\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("--jobs", type=positive)\nprint(p.parse_args(["--jobs", "4"]).jobs) # 4', 'p = argparse.ArgumentParser(prog="tool")\nsub = p.add_subparsers(dest="cmd", required=True) # dest= stores which command was chosen\n\nadd = sub.add_parser("add", help="add an item")\nadd.add_argument("item")\n\nrm = sub.add_parser("rm", help="remove an item")\nrm.add_argument("item")\nrm.add_argument("--force", action="store_true")\n\ndef do_add(args):\n print("adding", args.item)\n\nadd.set_defaults(func=do_add)\n\na = p.parse_args(["rm", "x", "--force"])\nprint(a.cmd, a.item, a.force) # rm x True\n\na = p.parse_args(["add", "milk"])\na.func(a) # adding milk', 'p = argparse.ArgumentParser(prog="tool", epilog="Example: tool --json")\ng = p.add_mutually_exclusive_group() # one or the other, never both\ng.add_argument("--json", action="store_true")\ng.add_argument("--csv", action="store_true")\nprint(p.format_usage(), end="") # usage: tool [-h] [--json | --csv]\n\np.add_argument("--out", metavar="FILE", help="where to save")\np.add_argument("--version", action="version", version="1.0")\nprint(p.parse_known_args(["--json", "--x"])[1]) # [\'--x\']', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--count")\nprint(repr(p.parse_args(["--count", "3"]).count)) # \'3\'', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Fix: use action="store_true" for a flag.
append with a default list. The values are added to the default. They do not replace it:
p.add_argument("-I", action="append", default=["."]) print(p.parse_args(["-I", "src"]).I) # ['.', 'src']
setup added so this can run · re-runs 10 earlier blocks on this page first
# Lightweight mock for objects whose attributes/methods aren't critical class _AutoMock: def __init__(self, name='mock'): self._name = name def __getattr__(self, k): return _AutoMock(self._name + '.' + k) def __call__(self, *a, **kw): print('-> ' + self._name + '() called') return _AutoMock(self._name + '()') def __repr__(self): return '<mock ' + self._name + '>' def __str__(self): return '<mock ' + self._name + '>' def __bool__(self): return True def __iter__(self): return iter([]) def __len__(self): return 0 def __getitem__(self, k): return _AutoMock(self._name + '[...]') def __setitem__(self, k, v): pass def __enter__(self): return self def __exit__(self, *a): return False async def __aenter__(self): return self async def __aexit__(self, *a): return False def __add__(self, o): return self def __radd__(self, o): return self def __sub__(self, o): return self def __mul__(self, o): return self def __rmul__(self, o): return self def __truediv__(self, o): return self def __eq__(self, o): return isinstance(o, _AutoMock) def __hash__(self): return hash(self._name) def __lt__(self, o): return True def __le__(self, o): return True def __gt__(self, o): return False def __ge__(self, o): return False def __mro_entries__(self, bases): return (object,) p = _AutoMock('p') argparse = _AutoMock('argparse') Path = _AutoMock('Path') # Earlier blocks on this page that this one builds on, re-run quietly first. try: import argparse from pathlib import Path from argparse import BooleanOptionalAction from argparse import ArgumentTypeError except Exception: pass _pm_earlier = [ 'import argparse\nfrom pathlib import Path\n\np = argparse.ArgumentParser(prog="tool", description="Resize images.")\np.add_argument("path") # a positional argument: required\np.add_argument("out", nargs="?", default="out.png") # a positional argument you may leave out\np.add_argument("--size", type=int, default=800) # an option: its name starts with --\n\nargs = p.parse_args(["cat.png"])\nprint(vars(args)) # {\'path\': \'cat.png\', \'out\': \'out.png\', \'size\': 800}\nprint(args.path) # cat.png\nprint(p.parse_args(["a", "--size", "9"]).size) # 9\nprint(p.parse_args(["a", "--size=9"]).size) # 9', 'from argparse import BooleanOptionalAction\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("-v", "--verbose", action="store_true")\np.add_argument("--dry-run", action="store_true")\np.add_argument("--no-cache", dest="cache", action="store_false")\np.add_argument("--color", default=True, action=BooleanOptionalAction)\n\nprint(p.parse_args(["-v"]).verbose) # True\nprint(p.parse_args([]).verbose) # False\nprint(p.parse_args(["--dry-run"]).dry_run) # True\nprint(p.parse_args([]).cache) # True\nprint(p.parse_args(["--no-color"]).color) # False', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--ratio", type=float)\np.add_argument("--out", type=Path)\np.add_argument("--fmt", default="json", choices=["json", "csv"])\n\nprint(p.parse_args(["--ratio", "0.5"]).ratio) # 0.5\nprint(p.parse_args([]).ratio) # None\nprint(p.parse_args(["--out", "res"]).out.name) # res\nprint(p.parse_args(["--fmt", "csv"]).fmt) # csv', 'try:\n p.parse_args(["--fmt", "xml"])\nexcept SystemExit as e:\n print("exit code", e.code) # exit code 2', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("-p", nargs=2, type=int) # exactly 2 values, such as a point\np.add_argument("--tag", action="append") # repeat the flag to collect values\np.add_argument("-q", action="count", default=0) # counts how often the flag appears\np.add_argument("files", nargs="+") # one or more values, as a list\n\na = p.parse_args(["a.txt", "b.txt", "-p", "8", "6", "--tag", "a", "--tag", "b", "-qqq"])\nprint(a.files) # [\'a.txt\', \'b.txt\']\nprint(a.p) # [8, 6]\nprint(a.tag) # [\'a\', \'b\']\nprint(a.q) # 3', 'from argparse import ArgumentTypeError\n\ndef positive(text):\n n = int(text)\n if n > 0:\n return n\n raise ArgumentTypeError("need > 0")\n\np = argparse.ArgumentParser(prog="tool")\np.add_argument("--jobs", type=positive)\nprint(p.parse_args(["--jobs", "4"]).jobs) # 4', 'p = argparse.ArgumentParser(prog="tool")\nsub = p.add_subparsers(dest="cmd", required=True) # dest= stores which command was chosen\n\nadd = sub.add_parser("add", help="add an item")\nadd.add_argument("item")\n\nrm = sub.add_parser("rm", help="remove an item")\nrm.add_argument("item")\nrm.add_argument("--force", action="store_true")\n\ndef do_add(args):\n print("adding", args.item)\n\nadd.set_defaults(func=do_add)\n\na = p.parse_args(["rm", "x", "--force"])\nprint(a.cmd, a.item, a.force) # rm x True\n\na = p.parse_args(["add", "milk"])\na.func(a) # adding milk', 'p = argparse.ArgumentParser(prog="tool", epilog="Example: tool --json")\ng = p.add_mutually_exclusive_group() # one or the other, never both\ng.add_argument("--json", action="store_true")\ng.add_argument("--csv", action="store_true")\nprint(p.format_usage(), end="") # usage: tool [-h] [--json | --csv]\n\np.add_argument("--out", metavar="FILE", help="where to save")\np.add_argument("--version", action="version", version="1.0")\nprint(p.parse_known_args(["--json", "--x"])[1]) # [\'--x\']', 'p = argparse.ArgumentParser(prog="tool")\np.add_argument("--count")\nprint(repr(p.parse_args(["--count", "3"]).count)) # \'3\'', 'p.add_argument("--debug", type=bool)\nprint(p.parse_args(["--debug", "False"]).debug) # True', ] def _pm_run_earlier(_srcs, _g): import sys as _s, io as _io, warnings as _w for _src in _srcs: _o, _e = _s.stdout, _s.stderr _s.stdout = _s.stderr = _io.StringIO() try: with _w.catch_warnings(): _w.simplefilter('ignore') exec(compile(_src, '<earlier block>', 'exec'), _g) except (Exception, SystemExit): pass finally: _s.stdout, _s.stderr = _o, _e if 'matplotlib.pyplot' in _s.modules: _s.modules['matplotlib.pyplot'].close('all') # their plots belong to their own blocks _pm_run_earlier(_pm_earlier, globals()) del _pm_earlier, _pm_run_earlier
Fix: leave the default as None, then write args.I or ["."]. This gives ["."] when no -I was given.
args.dry-run. Python reads this as args.dry minus run. Write args.dry_run.
p.parse_args() in a notebook or a test. With no list, it reads the arguments that started the notebook or test runner, and fails. Pass a list: p.parse_args(["cat.png"]).
No dest= on subparsers. Without add_subparsers(dest="cmd"), args.cmd does not exist and you cannot tell which command ran.
See also
Found this useful? Share it with a friend who’s learning Python.