5
:author: Tshepang Lekhonkhobe
9
This tutorial is intended to be a gentle introduction to :mod:`argparse`, the
10
recommended command-line parsing module in the Python standard library.
14
There are two other modules that fulfill the same task, namely
15
:mod:`getopt` (an equivalent for :c:func:`getopt` from the C
16
language) and the deprecated :mod:`optparse`.
17
Note also that :mod:`argparse` is based on :mod:`optparse`,
18
and therefore very similar in terms of usage.
24
Let's show the sort of functionality that we are going to explore in this
25
introductory tutorial by making use of the :command:`ls` command:
30
cpython devguide prog.py pypy rm-unused-function.patch
32
ctypes_configure demo dotviewer include lib_pypy lib-python ...
35
drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
36
drwxr-xr-x 4 wena wena 4096 Feb 8 12:04 devguide
37
-rwxr-xr-x 1 wena wena 535 Feb 19 00:05 prog.py
38
drwxr-xr-x 14 wena wena 4096 Feb 7 00:59 pypy
39
-rw-r--r-- 1 wena wena 741 Feb 18 01:01 rm-unused-function.patch
41
Usage: ls [OPTION]... [FILE]...
42
List information about the FILEs (the current directory by default).
43
Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
46
A few concepts we can learn from the four commands:
48
* The :command:`ls` command is useful when run without any options at all. It defaults
49
to displaying the contents of the current directory.
51
* If we want beyond what it provides by default, we tell it a bit more. In
52
this case, we want it to display a different directory, ``pypy``.
53
What we did is specify what is known as a positional argument. It's named so
54
because the program should know what to do with the value, solely based on
55
where it appears on the command line. This concept is more relevant
56
to a command like :command:`cp`, whose most basic usage is ``cp SRC DEST``.
57
The first position is *what you want copied,* and the second
58
position is *where you want it copied to*.
60
* Now, say we want to change behaviour of the program. In our example,
61
we display more info for each file instead of just showing the file names.
62
The ``-l`` in that case is known as an optional argument.
64
* That's a snippet of the help text. It's very useful in that you can
65
come across a program you have never used before, and can figure out
66
how it works simply by reading its help text.
72
Let us start with a very simple example which does (almost) nothing::
75
parser = argparse.ArgumentParser()
78
Following is a result of running the code:
83
$ python3 prog.py --help
87
-h, --help show this help message and exit
88
$ python3 prog.py --verbose
90
prog.py: error: unrecognized arguments: --verbose
93
prog.py: error: unrecognized arguments: foo
95
Here is what is happening:
97
* Running the script without any options results in nothing displayed to
98
stdout. Not so useful.
100
* The second one starts to display the usefulness of the :mod:`argparse`
101
module. We have done almost nothing, but already we get a nice help message.
103
* The ``--help`` option, which can also be shortened to ``-h``, is the only
104
option we get for free (i.e. no need to specify it). Specifying anything
105
else results in an error. But even then, we do get a useful usage message,
109
Introducing Positional arguments
110
================================
115
parser = argparse.ArgumentParser()
116
parser.add_argument("echo")
117
args = parser.parse_args()
120
And running the code:
125
usage: prog.py [-h] echo
126
prog.py: error: the following arguments are required: echo
127
$ python3 prog.py --help
128
usage: prog.py [-h] echo
130
positional arguments:
134
-h, --help show this help message and exit
135
$ python3 prog.py foo
138
Here is what's happening:
140
* We've added the :meth:`add_argument` method, which is what we use to specify
141
which command-line options the program is willing to accept. In this case,
142
I've named it ``echo`` so that it's in line with its function.
144
* Calling our program now requires us to specify an option.
146
* The :meth:`parse_args` method actually returns some data from the
147
options specified, in this case, ``echo``.
149
* The variable is some form of 'magic' that :mod:`argparse` performs for free
150
(i.e. no need to specify which variable that value is stored in).
151
You will also notice that its name matches the string argument given
152
to the method, ``echo``.
154
Note however that, although the help display looks nice and all, it currently
155
is not as helpful as it can be. For example we see that we got ``echo`` as a
156
positional argument, but we don't know what it does, other than by guessing or
157
by reading the source code. So, let's make it a bit more useful::
160
parser = argparse.ArgumentParser()
161
parser.add_argument("echo", help="echo the string you use here")
162
args = parser.parse_args()
170
usage: prog.py [-h] echo
172
positional arguments:
173
echo echo the string you use here
176
-h, --help show this help message and exit
178
Now, how about doing something even more useful::
181
parser = argparse.ArgumentParser()
182
parser.add_argument("square", help="display a square of a given number")
183
args = parser.parse_args()
184
print(args.square**2)
186
Following is a result of running the code:
191
Traceback (most recent call last):
192
File "prog.py", line 5, in <module>
193
print(args.square**2)
194
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
196
That didn't go so well. That's because :mod:`argparse` treats the options we
197
give it as strings, unless we tell it otherwise. So, let's tell
198
:mod:`argparse` to treat that input as an integer::
201
parser = argparse.ArgumentParser()
202
parser.add_argument("square", help="display a square of a given number",
204
args = parser.parse_args()
205
print(args.square**2)
207
Following is a result of running the code:
213
$ python3 prog.py four
214
usage: prog.py [-h] square
215
prog.py: error: argument square: invalid int value: 'four'
217
That went well. The program now even helpfully quits on bad illegal input
221
Introducing Optional arguments
222
==============================
224
So far we, have been playing with positional arguments. Let us
225
have a look on how to add optional ones::
228
parser = argparse.ArgumentParser()
229
parser.add_argument("--verbosity", help="increase output verbosity")
230
args = parser.parse_args()
232
print("verbosity turned on")
238
$ python3 prog.py --verbosity 1
241
$ python3 prog.py --help
242
usage: prog.py [-h] [--verbosity VERBOSITY]
245
-h, --help show this help message and exit
246
--verbosity VERBOSITY
247
increase output verbosity
248
$ python3 prog.py --verbosity
249
usage: prog.py [-h] [--verbosity VERBOSITY]
250
prog.py: error: argument --verbosity: expected one argument
252
Here is what is happening:
254
* The program is written so as to display something when ``--verbosity`` is
255
specified and display nothing when not.
257
* To show that the option is actually optional, there is no error when running
258
the program without it. Note that by default, if an optional argument isn't
259
used, the relevant variable, in this case :attr:`args.verbosity`, is
260
given ``None`` as a value, which is the reason it fails the truth
261
test of the :keyword:`if` statement.
263
* The help message is a bit different.
265
* When using the ``--verbosity`` option, one must also specify some value,
268
The above example accepts arbitrary integer values for ``--verbosity``, but for
269
our simple program, only two values are actually useful, ``True`` or ``False``.
270
Let's modify the code accordingly::
273
parser = argparse.ArgumentParser()
274
parser.add_argument("--verbose", help="increase output verbosity",
276
args = parser.parse_args()
278
print("verbosity turned on")
284
$ python3 prog.py --verbose
286
$ python3 prog.py --verbose 1
287
usage: prog.py [-h] [--verbose]
288
prog.py: error: unrecognized arguments: 1
289
$ python3 prog.py --help
290
usage: prog.py [-h] [--verbose]
293
-h, --help show this help message and exit
294
--verbose increase output verbosity
296
Here is what is happening:
298
* The option is now more of a flag than something that requires a value.
299
We even changed the name of the option to match that idea.
300
Note that we now specify a new keyword, ``action``, and give it the value
301
``"store_true"``. This means that, if the option is specified,
302
assign the value ``True`` to :data:`args.verbose`.
303
Not specifying it implies ``False``.
305
* It complains when you specify a value, in true spirit of what flags
308
* Notice the different help text.
314
If you are familiar with command line usage,
315
you will notice that I haven't yet touched on the topic of short
316
versions of the options. It's quite simple::
319
parser = argparse.ArgumentParser()
320
parser.add_argument("-v", "--verbose", help="increase output verbosity",
322
args = parser.parse_args()
324
print("verbosity turned on")
332
$ python3 prog.py --help
333
usage: prog.py [-h] [-v]
336
-h, --help show this help message and exit
337
-v, --verbose increase output verbosity
339
Note that the new ability is also reflected in the help text.
342
Combining Positional and Optional arguments
343
===========================================
345
Our program keeps growing in complexity::
348
parser = argparse.ArgumentParser()
349
parser.add_argument("square", type=int,
350
help="display a square of a given number")
351
parser.add_argument("-v", "--verbose", action="store_true",
352
help="increase output verbosity")
353
args = parser.parse_args()
354
answer = args.square**2
356
print("the square of {} equals {}".format(args.square, answer))
365
usage: prog.py [-h] [-v] square
366
prog.py: error: the following arguments are required: square
369
$ python3 prog.py 4 --verbose
370
the square of 4 equals 16
371
$ python3 prog.py --verbose 4
372
the square of 4 equals 16
374
* We've brought back a positional argument, hence the complaint.
376
* Note that the order does not matter.
378
How about we give this program of ours back the ability to have
379
multiple verbosity values, and actually get to use them::
382
parser = argparse.ArgumentParser()
383
parser.add_argument("square", type=int,
384
help="display a square of a given number")
385
parser.add_argument("-v", "--verbosity", type=int,
386
help="increase output verbosity")
387
args = parser.parse_args()
388
answer = args.square**2
389
if args.verbosity == 2:
390
print("the square of {} equals {}".format(args.square, answer))
391
elif args.verbosity == 1:
392
print("{}^2 == {}".format(args.square, answer))
402
$ python3 prog.py 4 -v
403
usage: prog.py [-h] [-v VERBOSITY] square
404
prog.py: error: argument -v/--verbosity: expected one argument
405
$ python3 prog.py 4 -v 1
407
$ python3 prog.py 4 -v 2
408
the square of 4 equals 16
409
$ python3 prog.py 4 -v 3
412
These all look good except the last one, which exposes a bug in our program.
413
Let's fix it by restricting the values the ``--verbosity`` option can accept::
416
parser = argparse.ArgumentParser()
417
parser.add_argument("square", type=int,
418
help="display a square of a given number")
419
parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
420
help="increase output verbosity")
421
args = parser.parse_args()
422
answer = args.square**2
423
if args.verbosity == 2:
424
print("the square of {} equals {}".format(args.square, answer))
425
elif args.verbosity == 1:
426
print("{}^2 == {}".format(args.square, answer))
434
$ python3 prog.py 4 -v 3
435
usage: prog.py [-h] [-v {0,1,2}] square
436
prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)
437
$ python3 prog.py 4 -h
438
usage: prog.py [-h] [-v {0,1,2}] square
440
positional arguments:
441
square display a square of a given number
444
-h, --help show this help message and exit
445
-v {0,1,2}, --verbosity {0,1,2}
446
increase output verbosity
448
Note that the change also reflects both in the error message as well as the
451
Now, let's use a different approach of playing with verbosity, which is pretty
452
common. It also matches the way the CPython executable handles its own
453
verbosity argument (check the output of ``python --help``)::
456
parser = argparse.ArgumentParser()
457
parser.add_argument("square", type=int,
458
help="display the square of a given number")
459
parser.add_argument("-v", "--verbosity", action="count",
460
help="increase output verbosity")
461
args = parser.parse_args()
462
answer = args.square**2
463
if args.verbosity == 2:
464
print("the square of {} equals {}".format(args.square, answer))
465
elif args.verbosity == 1:
466
print("{}^2 == {}".format(args.square, answer))
470
We have introduced another action, "count",
471
to count the number of occurrences of a specific optional arguments:
477
$ python3 prog.py 4 -v
479
$ python3 prog.py 4 -vv
480
the square of 4 equals 16
481
$ python3 prog.py 4 --verbosity --verbosity
482
the square of 4 equals 16
483
$ python3 prog.py 4 -v 1
484
usage: prog.py [-h] [-v] square
485
prog.py: error: unrecognized arguments: 1
486
$ python3 prog.py 4 -h
487
usage: prog.py [-h] [-v] square
489
positional arguments:
490
square display a square of a given number
493
-h, --help show this help message and exit
494
-v, --verbosity increase output verbosity
495
$ python3 prog.py 4 -vvv
498
* Yes, it's now more of a flag (similar to ``action="store_true"``) in the
499
previous version of our script. That should explain the complaint.
501
* It also behaves similar to "store_true" action.
503
* Now here's a demonstration of what the "count" action gives. You've probably
504
seen this sort of usage before.
506
* And, just like the "store_true" action, if you don't specify the ``-v`` flag,
507
that flag is considered to have ``None`` value.
509
* As should be expected, specifying the long form of the flag, we should get
512
* Sadly, our help output isn't very informative on the new ability our script
513
has acquired, but that can always be fixed by improving the documentation for
514
out script (e.g. via the ``help`` keyword argument).
516
* That last output exposes a bug in our program.
522
parser = argparse.ArgumentParser()
523
parser.add_argument("square", type=int,
524
help="display a square of a given number")
525
parser.add_argument("-v", "--verbosity", action="count",
526
help="increase output verbosity")
527
args = parser.parse_args()
528
answer = args.square**2
530
# bugfix: replace == with >=
531
if args.verbosity >= 2:
532
print("the square of {} equals {}".format(args.square, answer))
533
elif args.verbosity >= 1:
534
print("{}^2 == {}".format(args.square, answer))
538
And this is what it gives:
542
$ python3 prog.py 4 -vvv
543
the square of 4 equals 16
544
$ python3 prog.py 4 -vvvv
545
the square of 4 equals 16
547
Traceback (most recent call last):
548
File "prog.py", line 11, in <module>
549
if args.verbosity >= 2:
550
TypeError: unorderable types: NoneType() >= int()
552
* First output went well, and fixes the bug we had before.
553
That is, we want any value >= 2 to be as verbose as possible.
555
* Third output not so good.
560
parser = argparse.ArgumentParser()
561
parser.add_argument("square", type=int,
562
help="display a square of a given number")
563
parser.add_argument("-v", "--verbosity", action="count", default=0,
564
help="increase output verbosity")
565
args = parser.parse_args()
566
answer = args.square**2
567
if args.verbosity >= 2:
568
print("the square of {} equals {}".format(args.square, answer))
569
elif args.verbosity >= 1:
570
print("{}^2 == {}".format(args.square, answer))
574
We've just introduced yet another keyword, ``default``.
575
We've set it to ``0`` in order to make it comparable to the other int values.
576
Remember that by default,
577
if an optional argument isn't specified,
578
it gets the ``None`` value, and that cannot be compared to an int value
579
(hence the :exc:`TypeError` exception).
588
You can go quite far just with what we've learned so far,
589
and we have only scratched the surface.
590
The :mod:`argparse` module is very powerful,
591
and we'll explore a bit more of it before we end this tutorial.
594
Getting a little more advanced
595
==============================
597
What if we wanted to expand our tiny program to perform other powers,
601
parser = argparse.ArgumentParser()
602
parser.add_argument("x", type=int, help="the base")
603
parser.add_argument("y", type=int, help="the exponent")
604
parser.add_argument("-v", "--verbosity", action="count", default=0)
605
args = parser.parse_args()
606
answer = args.x**args.y
607
if args.verbosity >= 2:
608
print("{} to the power {} equals {}".format(args.x, args.y, answer))
609
elif args.verbosity >= 1:
610
print("{}^{} == {}".format(args.x, args.y, answer))
619
usage: prog.py [-h] [-v] x y
620
prog.py: error: the following arguments are required: x, y
622
usage: prog.py [-h] [-v] x y
624
positional arguments:
629
-h, --help show this help message and exit
631
$ python3 prog.py 4 2 -v
635
Notice that so far we've been using verbosity level to *change* the text
636
that gets displayed. The following example instead uses verbosity level
637
to display *more* text instead::
640
parser = argparse.ArgumentParser()
641
parser.add_argument("x", type=int, help="the base")
642
parser.add_argument("y", type=int, help="the exponent")
643
parser.add_argument("-v", "--verbosity", action="count", default=0)
644
args = parser.parse_args()
645
answer = args.x**args.y
646
if args.verbosity >= 2:
647
print("Running '{}'".format(__file__))
648
if args.verbosity >= 1:
649
print("{}^{} == ".format(args.x, args.y), end="")
656
$ python3 prog.py 4 2
658
$ python3 prog.py 4 2 -v
660
$ python3 prog.py 4 2 -vv
668
So far, we have been working with two methods of an
669
:class:`argparse.ArgumentParser` instance. Let's introduce a third one,
670
:meth:`add_mutually_exclusive_group`. It allows for us to specify options that
671
conflict with each other. Let's also change the rest of the program so that
672
the new functionality makes more sense:
673
we'll introduce the ``--quiet`` option,
674
which will be the opposite of the ``--verbose`` one::
678
parser = argparse.ArgumentParser()
679
group = parser.add_mutually_exclusive_group()
680
group.add_argument("-v", "--verbose", action="store_true")
681
group.add_argument("-q", "--quiet", action="store_true")
682
parser.add_argument("x", type=int, help="the base")
683
parser.add_argument("y", type=int, help="the exponent")
684
args = parser.parse_args()
685
answer = args.x**args.y
690
print("{} to the power {} equals {}".format(args.x, args.y, answer))
692
print("{}^{} == {}".format(args.x, args.y, answer))
694
Our program is now simpler, and we've lost some functionality for the sake of
695
demonstration. Anyways, here's the output:
699
$ python3 prog.py 4 2
701
$ python3 prog.py 4 2 -q
703
$ python3 prog.py 4 2 -v
704
4 to the power 2 equals 16
705
$ python3 prog.py 4 2 -vq
706
usage: prog.py [-h] [-v | -q] x y
707
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
708
$ python3 prog.py 4 2 -v --quiet
709
usage: prog.py [-h] [-v | -q] x y
710
prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
712
That should be easy to follow. I've added that last output so you can see the
713
sort of flexibility you get, i.e. mixing long form options with short form
716
Before we conclude, you probably want to tell your users the main purpose of
717
your program, just in case they don't know::
721
parser = argparse.ArgumentParser(description="calculate X to the power of Y")
722
group = parser.add_mutually_exclusive_group()
723
group.add_argument("-v", "--verbose", action="store_true")
724
group.add_argument("-q", "--quiet", action="store_true")
725
parser.add_argument("x", type=int, help="the base")
726
parser.add_argument("y", type=int, help="the exponent")
727
args = parser.parse_args()
728
answer = args.x**args.y
733
print("{} to the power {} equals {}".format(args.x, args.y, answer))
735
print("{}^{} == {}".format(args.x, args.y, answer))
737
Note that slight difference in the usage text. Note the ``[-v | -q]``,
738
which tells us that we can either use ``-v`` or ``-q``,
739
but not both at the same time:
743
$ python3 prog.py --help
744
usage: prog.py [-h] [-v | -q] x y
746
calculate X to the power of Y
748
positional arguments:
753
-h, --help show this help message and exit
761
The :mod:`argparse` module offers a lot more than shown here.
762
Its docs are quite detailed and thorough, and full of examples.
763
Having gone through this tutorial, you should easily digest them
764
without feeling overwhelmed.