• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1*****************
2Argparse Tutorial
3*****************
4
5:author: Tshepang Lekhonkhobe
6
7.. _argparse-tutorial:
8
9This tutorial is intended to be a gentle introduction to :mod:`argparse`, the
10recommended command-line parsing module in the Python standard library.
11This was written for argparse in Python 3. A few details are different in 2.x,
12especially some exception messages, which were improved in 3.x.
13
14.. note::
15
16   There are two other modules that fulfill the same task, namely
17   :mod:`getopt` (an equivalent for :c:func:`getopt` from the C
18   language) and the deprecated :mod:`optparse`.
19   Note also that :mod:`argparse` is based on :mod:`optparse`,
20   and therefore very similar in terms of usage.
21
22
23Concepts
24========
25
26Let's show the sort of functionality that we are going to explore in this
27introductory tutorial by making use of the :command:`ls` command:
28
29.. code-block:: sh
30
31   $ ls
32   cpython  devguide  prog.py  pypy  rm-unused-function.patch
33   $ ls pypy
34   ctypes_configure  demo  dotviewer  include  lib_pypy  lib-python ...
35   $ ls -l
36   total 20
37   drwxr-xr-x 19 wena wena 4096 Feb 18 18:51 cpython
38   drwxr-xr-x  4 wena wena 4096 Feb  8 12:04 devguide
39   -rwxr-xr-x  1 wena wena  535 Feb 19 00:05 prog.py
40   drwxr-xr-x 14 wena wena 4096 Feb  7 00:59 pypy
41   -rw-r--r--  1 wena wena  741 Feb 18 01:01 rm-unused-function.patch
42   $ ls --help
43   Usage: ls [OPTION]... [FILE]...
44   List information about the FILEs (the current directory by default).
45   Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.
46   ...
47
48A few concepts we can learn from the four commands:
49
50* The :command:`ls` command is useful when run without any options at all. It defaults
51  to displaying the contents of the current directory.
52
53* If we want beyond what it provides by default, we tell it a bit more. In
54  this case, we want it to display a different directory, ``pypy``.
55  What we did is specify what is known as a positional argument. It's named so
56  because the program should know what to do with the value, solely based on
57  where it appears on the command line. This concept is more relevant
58  to a command like :command:`cp`, whose most basic usage is ``cp SRC DEST``.
59  The first position is *what you want copied,* and the second
60  position is *where you want it copied to*.
61
62* Now, say we want to change behaviour of the program. In our example,
63  we display more info for each file instead of just showing the file names.
64  The ``-l`` in that case is known as an optional argument.
65
66* That's a snippet of the help text. It's very useful in that you can
67  come across a program you have never used before, and can figure out
68  how it works simply by reading its help text.
69
70
71The basics
72==========
73
74Let us start with a very simple example which does (almost) nothing::
75
76   import argparse
77   parser = argparse.ArgumentParser()
78   parser.parse_args()
79
80Following is a result of running the code:
81
82.. code-block:: sh
83
84   $ python prog.py
85   $ python prog.py --help
86   usage: prog.py [-h]
87
88   optional arguments:
89     -h, --help  show this help message and exit
90   $ python prog.py --verbose
91   usage: prog.py [-h]
92   prog.py: error: unrecognized arguments: --verbose
93   $ python prog.py foo
94   usage: prog.py [-h]
95   prog.py: error: unrecognized arguments: foo
96
97Here is what is happening:
98
99* Running the script without any options results in nothing displayed to
100  stdout. Not so useful.
101
102* The second one starts to display the usefulness of the :mod:`argparse`
103  module. We have done almost nothing, but already we get a nice help message.
104
105* The ``--help`` option, which can also be shortened to ``-h``, is the only
106  option we get for free (i.e. no need to specify it). Specifying anything
107  else results in an error. But even then, we do get a useful usage message,
108  also for free.
109
110
111Introducing Positional arguments
112================================
113
114An example::
115
116   import argparse
117   parser = argparse.ArgumentParser()
118   parser.add_argument("echo")
119   args = parser.parse_args()
120   print args.echo
121
122And running the code:
123
124.. code-block:: sh
125
126   $ python prog.py
127   usage: prog.py [-h] echo
128   prog.py: error: the following arguments are required: echo
129   $ python prog.py --help
130   usage: prog.py [-h] echo
131
132   positional arguments:
133     echo
134
135   optional arguments:
136     -h, --help  show this help message and exit
137   $ python prog.py foo
138   foo
139
140Here is what's happening:
141
142* We've added the :meth:`add_argument` method, which is what we use to specify
143  which command-line options the program is willing to accept. In this case,
144  I've named it ``echo`` so that it's in line with its function.
145
146* Calling our program now requires us to specify an option.
147
148* The :meth:`parse_args` method actually returns some data from the
149  options specified, in this case, ``echo``.
150
151* The variable is some form of 'magic' that :mod:`argparse` performs for free
152  (i.e. no need to specify which variable that value is stored in).
153  You will also notice that its name matches the string argument given
154  to the method, ``echo``.
155
156Note however that, although the help display looks nice and all, it currently
157is not as helpful as it can be. For example we see that we got ``echo`` as a
158positional argument, but we don't know what it does, other than by guessing or
159by reading the source code. So, let's make it a bit more useful::
160
161   import argparse
162   parser = argparse.ArgumentParser()
163   parser.add_argument("echo", help="echo the string you use here")
164   args = parser.parse_args()
165   print args.echo
166
167And we get:
168
169.. code-block:: sh
170
171   $ python prog.py -h
172   usage: prog.py [-h] echo
173
174   positional arguments:
175     echo        echo the string you use here
176
177   optional arguments:
178     -h, --help  show this help message and exit
179
180Now, how about doing something even more useful::
181
182   import argparse
183   parser = argparse.ArgumentParser()
184   parser.add_argument("square", help="display a square of a given number")
185   args = parser.parse_args()
186   print args.square**2
187
188Following is a result of running the code:
189
190.. code-block:: sh
191
192   $ python prog.py 4
193   Traceback (most recent call last):
194     File "prog.py", line 5, in <module>
195       print args.square**2
196   TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
197
198That didn't go so well. That's because :mod:`argparse` treats the options we
199give it as strings, unless we tell it otherwise. So, let's tell
200:mod:`argparse` to treat that input as an integer::
201
202   import argparse
203   parser = argparse.ArgumentParser()
204   parser.add_argument("square", help="display a square of a given number",
205                       type=int)
206   args = parser.parse_args()
207   print args.square**2
208
209Following is a result of running the code:
210
211.. code-block:: sh
212
213   $ python prog.py 4
214   16
215   $ python prog.py four
216   usage: prog.py [-h] square
217   prog.py: error: argument square: invalid int value: 'four'
218
219That went well. The program now even helpfully quits on bad illegal input
220before proceeding.
221
222
223Introducing Optional arguments
224==============================
225
226So far we have been playing with positional arguments. Let us
227have a look on how to add optional ones::
228
229   import argparse
230   parser = argparse.ArgumentParser()
231   parser.add_argument("--verbosity", help="increase output verbosity")
232   args = parser.parse_args()
233   if args.verbosity:
234       print "verbosity turned on"
235
236And the output:
237
238.. code-block:: sh
239
240   $ python prog.py --verbosity 1
241   verbosity turned on
242   $ python prog.py
243   $ python prog.py --help
244   usage: prog.py [-h] [--verbosity VERBOSITY]
245
246   optional arguments:
247     -h, --help            show this help message and exit
248     --verbosity VERBOSITY
249                           increase output verbosity
250   $ python prog.py --verbosity
251   usage: prog.py [-h] [--verbosity VERBOSITY]
252   prog.py: error: argument --verbosity: expected one argument
253
254Here is what is happening:
255
256* The program is written so as to display something when ``--verbosity`` is
257  specified and display nothing when not.
258
259* To show that the option is actually optional, there is no error when running
260  the program without it. Note that by default, if an optional argument isn't
261  used, the relevant variable, in this case :attr:`args.verbosity`, is
262  given ``None`` as a value, which is the reason it fails the truth
263  test of the :keyword:`if` statement.
264
265* The help message is a bit different.
266
267* When using the ``--verbosity`` option, one must also specify some value,
268  any value.
269
270The above example accepts arbitrary integer values for ``--verbosity``, but for
271our simple program, only two values are actually useful, ``True`` or ``False``.
272Let's modify the code accordingly::
273
274   import argparse
275   parser = argparse.ArgumentParser()
276   parser.add_argument("--verbose", help="increase output verbosity",
277                       action="store_true")
278   args = parser.parse_args()
279   if args.verbose:
280      print "verbosity turned on"
281
282And the output:
283
284.. code-block:: sh
285
286   $ python prog.py --verbose
287   verbosity turned on
288   $ python prog.py --verbose 1
289   usage: prog.py [-h] [--verbose]
290   prog.py: error: unrecognized arguments: 1
291   $ python prog.py --help
292   usage: prog.py [-h] [--verbose]
293
294   optional arguments:
295     -h, --help  show this help message and exit
296     --verbose   increase output verbosity
297
298Here is what is happening:
299
300* The option is now more of a flag than something that requires a value.
301  We even changed the name of the option to match that idea.
302  Note that we now specify a new keyword, ``action``, and give it the value
303  ``"store_true"``. This means that, if the option is specified,
304  assign the value ``True`` to :data:`args.verbose`.
305  Not specifying it implies ``False``.
306
307* It complains when you specify a value, in true spirit of what flags
308  actually are.
309
310* Notice the different help text.
311
312
313Short options
314-------------
315
316If you are familiar with command line usage,
317you will notice that I haven't yet touched on the topic of short
318versions of the options. It's quite simple::
319
320   import argparse
321   parser = argparse.ArgumentParser()
322   parser.add_argument("-v", "--verbose", help="increase output verbosity",
323                       action="store_true")
324   args = parser.parse_args()
325   if args.verbose:
326       print "verbosity turned on"
327
328And here goes:
329
330.. code-block:: sh
331
332   $ python prog.py -v
333   verbosity turned on
334   $ python prog.py --help
335   usage: prog.py [-h] [-v]
336
337   optional arguments:
338     -h, --help     show this help message and exit
339     -v, --verbose  increase output verbosity
340
341Note that the new ability is also reflected in the help text.
342
343
344Combining Positional and Optional arguments
345===========================================
346
347Our program keeps growing in complexity::
348
349   import argparse
350   parser = argparse.ArgumentParser()
351   parser.add_argument("square", type=int,
352                       help="display a square of a given number")
353   parser.add_argument("-v", "--verbose", action="store_true",
354                       help="increase output verbosity")
355   args = parser.parse_args()
356   answer = args.square**2
357   if args.verbose:
358       print "the square of {} equals {}".format(args.square, answer)
359   else:
360       print answer
361
362And now the output:
363
364.. code-block:: sh
365
366   $ python prog.py
367   usage: prog.py [-h] [-v] square
368   prog.py: error: the following arguments are required: square
369   $ python prog.py 4
370   16
371   $ python prog.py 4 --verbose
372   the square of 4 equals 16
373   $ python prog.py --verbose 4
374   the square of 4 equals 16
375
376* We've brought back a positional argument, hence the complaint.
377
378* Note that the order does not matter.
379
380How about we give this program of ours back the ability to have
381multiple verbosity values, and actually get to use them::
382
383   import argparse
384   parser = argparse.ArgumentParser()
385   parser.add_argument("square", type=int,
386                       help="display a square of a given number")
387   parser.add_argument("-v", "--verbosity", type=int,
388                       help="increase output verbosity")
389   args = parser.parse_args()
390   answer = args.square**2
391   if args.verbosity == 2:
392       print "the square of {} equals {}".format(args.square, answer)
393   elif args.verbosity == 1:
394       print "{}^2 == {}".format(args.square, answer)
395   else:
396       print answer
397
398And the output:
399
400.. code-block:: sh
401
402   $ python prog.py 4
403   16
404   $ python prog.py 4 -v
405   usage: prog.py [-h] [-v VERBOSITY] square
406   prog.py: error: argument -v/--verbosity: expected one argument
407   $ python prog.py 4 -v 1
408   4^2 == 16
409   $ python prog.py 4 -v 2
410   the square of 4 equals 16
411   $ python prog.py 4 -v 3
412   16
413
414These all look good except the last one, which exposes a bug in our program.
415Let's fix it by restricting the values the ``--verbosity`` option can accept::
416
417   import argparse
418   parser = argparse.ArgumentParser()
419   parser.add_argument("square", type=int,
420                       help="display a square of a given number")
421   parser.add_argument("-v", "--verbosity", type=int, choices=[0, 1, 2],
422                       help="increase output verbosity")
423   args = parser.parse_args()
424   answer = args.square**2
425   if args.verbosity == 2:
426       print "the square of {} equals {}".format(args.square, answer)
427   elif args.verbosity == 1:
428       print "{}^2 == {}".format(args.square, answer)
429   else:
430       print answer
431
432And the output:
433
434.. code-block:: sh
435
436   $ python prog.py 4 -v 3
437   usage: prog.py [-h] [-v {0,1,2}] square
438   prog.py: error: argument -v/--verbosity: invalid choice: 3 (choose from 0, 1, 2)
439   $ python prog.py 4 -h
440   usage: prog.py [-h] [-v {0,1,2}] square
441
442   positional arguments:
443     square                display a square of a given number
444
445   optional arguments:
446     -h, --help            show this help message and exit
447     -v {0,1,2}, --verbosity {0,1,2}
448                           increase output verbosity
449
450Note that the change also reflects both in the error message as well as the
451help string.
452
453Now, let's use a different approach of playing with verbosity, which is pretty
454common. It also matches the way the CPython executable handles its own
455verbosity argument (check the output of ``python --help``)::
456
457   import argparse
458   parser = argparse.ArgumentParser()
459   parser.add_argument("square", type=int,
460                       help="display the square of a given number")
461   parser.add_argument("-v", "--verbosity", action="count",
462                       help="increase output verbosity")
463   args = parser.parse_args()
464   answer = args.square**2
465   if args.verbosity == 2:
466       print "the square of {} equals {}".format(args.square, answer)
467   elif args.verbosity == 1:
468       print "{}^2 == {}".format(args.square, answer)
469   else:
470       print answer
471
472We have introduced another action, "count",
473to count the number of occurrences of a specific optional arguments:
474
475.. code-block:: sh
476
477   $ python prog.py 4
478   16
479   $ python prog.py 4 -v
480   4^2 == 16
481   $ python prog.py 4 -vv
482   the square of 4 equals 16
483   $ python prog.py 4 --verbosity --verbosity
484   the square of 4 equals 16
485   $ python prog.py 4 -v 1
486   usage: prog.py [-h] [-v] square
487   prog.py: error: unrecognized arguments: 1
488   $ python prog.py 4 -h
489   usage: prog.py [-h] [-v] square
490
491   positional arguments:
492     square           display a square of a given number
493
494   optional arguments:
495     -h, --help       show this help message and exit
496     -v, --verbosity  increase output verbosity
497   $ python prog.py 4 -vvv
498   16
499
500* Yes, it's now more of a flag (similar to ``action="store_true"``) in the
501  previous version of our script. That should explain the complaint.
502
503* It also behaves similar to "store_true" action.
504
505* Now here's a demonstration of what the "count" action gives. You've probably
506  seen this sort of usage before.
507
508* And, just like the "store_true" action, if you don't specify the ``-v`` flag,
509  that flag is considered to have ``None`` value.
510
511* As should be expected, specifying the long form of the flag, we should get
512  the same output.
513
514* Sadly, our help output isn't very informative on the new ability our script
515  has acquired, but that can always be fixed by improving the documentation for
516  our script (e.g. via the ``help`` keyword argument).
517
518* That last output exposes a bug in our program.
519
520
521Let's fix::
522
523   import argparse
524   parser = argparse.ArgumentParser()
525   parser.add_argument("square", type=int,
526                       help="display a square of a given number")
527   parser.add_argument("-v", "--verbosity", action="count",
528                       help="increase output verbosity")
529   args = parser.parse_args()
530   answer = args.square**2
531
532   # bugfix: replace == with >=
533   if args.verbosity >= 2:
534       print "the square of {} equals {}".format(args.square, answer)
535   elif args.verbosity >= 1:
536       print "{}^2 == {}".format(args.square, answer)
537   else:
538       print answer
539
540And this is what it gives:
541
542.. code-block:: sh
543
544   $ python prog.py 4 -vvv
545   the square of 4 equals 16
546   $ python prog.py 4 -vvvv
547   the square of 4 equals 16
548   $ python prog.py 4
549   Traceback (most recent call last):
550     File "prog.py", line 11, in <module>
551       if args.verbosity >= 2:
552   TypeError: unorderable types: NoneType() >= int()
553
554* First output went well, and fixes the bug we had before.
555  That is, we want any value >= 2 to be as verbose as possible.
556
557* Third output not so good.
558
559Let's fix that bug::
560
561   import argparse
562   parser = argparse.ArgumentParser()
563   parser.add_argument("square", type=int,
564                       help="display a square of a given number")
565   parser.add_argument("-v", "--verbosity", action="count", default=0,
566                       help="increase output verbosity")
567   args = parser.parse_args()
568   answer = args.square**2
569   if args.verbosity >= 2:
570       print "the square of {} equals {}".format(args.square, answer)
571   elif args.verbosity >= 1:
572       print "{}^2 == {}".format(args.square, answer)
573   else:
574       print answer
575
576We've just introduced yet another keyword, ``default``.
577We've set it to ``0`` in order to make it comparable to the other int values.
578Remember that by default,
579if an optional argument isn't specified,
580it gets the ``None`` value, and that cannot be compared to an int value
581(hence the :exc:`TypeError` exception).
582
583And:
584
585.. code-block:: sh
586
587   $ python prog.py 4
588   16
589
590You can go quite far just with what we've learned so far,
591and we have only scratched the surface.
592The :mod:`argparse` module is very powerful,
593and we'll explore a bit more of it before we end this tutorial.
594
595
596Getting a little more advanced
597==============================
598
599What if we wanted to expand our tiny program to perform other powers,
600not just squares::
601
602   import argparse
603   parser = argparse.ArgumentParser()
604   parser.add_argument("x", type=int, help="the base")
605   parser.add_argument("y", type=int, help="the exponent")
606   parser.add_argument("-v", "--verbosity", action="count", default=0)
607   args = parser.parse_args()
608   answer = args.x**args.y
609   if args.verbosity >= 2:
610       print "{} to the power {} equals {}".format(args.x, args.y, answer)
611   elif args.verbosity >= 1:
612       print "{}^{} == {}".format(args.x, args.y, answer)
613   else:
614       print answer
615
616Output:
617
618.. code-block:: sh
619
620   $ python prog.py
621   usage: prog.py [-h] [-v] x y
622   prog.py: error: the following arguments are required: x, y
623   $ python prog.py -h
624   usage: prog.py [-h] [-v] x y
625
626   positional arguments:
627     x                the base
628     y                the exponent
629
630   optional arguments:
631     -h, --help       show this help message and exit
632     -v, --verbosity
633   $ python prog.py 4 2 -v
634   4^2 == 16
635
636
637Notice that so far we've been using verbosity level to *change* the text
638that gets displayed. The following example instead uses verbosity level
639to display *more* text instead::
640
641   import argparse
642   parser = argparse.ArgumentParser()
643   parser.add_argument("x", type=int, help="the base")
644   parser.add_argument("y", type=int, help="the exponent")
645   parser.add_argument("-v", "--verbosity", action="count", default=0)
646   args = parser.parse_args()
647   answer = args.x**args.y
648   if args.verbosity >= 2:
649       print "Running '{}'".format(__file__)
650   if args.verbosity >= 1:
651       print "{}^{} ==".format(args.x, args.y),
652   print answer
653
654Output:
655
656.. code-block:: sh
657
658   $ python prog.py 4 2
659   16
660   $ python prog.py 4 2 -v
661   4^2 == 16
662   $ python prog.py 4 2 -vv
663   Running 'prog.py'
664   4^2 == 16
665
666
667Conflicting options
668-------------------
669
670So far, we have been working with two methods of an
671:class:`argparse.ArgumentParser` instance. Let's introduce a third one,
672:meth:`add_mutually_exclusive_group`. It allows for us to specify options that
673conflict with each other. Let's also change the rest of the program so that
674the new functionality makes more sense:
675we'll introduce the ``--quiet`` option,
676which will be the opposite of the ``--verbose`` one::
677
678   import argparse
679
680   parser = argparse.ArgumentParser()
681   group = parser.add_mutually_exclusive_group()
682   group.add_argument("-v", "--verbose", action="store_true")
683   group.add_argument("-q", "--quiet", action="store_true")
684   parser.add_argument("x", type=int, help="the base")
685   parser.add_argument("y", type=int, help="the exponent")
686   args = parser.parse_args()
687   answer = args.x**args.y
688
689   if args.quiet:
690       print answer
691   elif args.verbose:
692       print "{} to the power {} equals {}".format(args.x, args.y, answer)
693   else:
694       print "{}^{} == {}".format(args.x, args.y, answer)
695
696Our program is now simpler, and we've lost some functionality for the sake of
697demonstration. Anyways, here's the output:
698
699.. code-block:: sh
700
701   $ python prog.py 4 2
702   4^2 == 16
703   $ python prog.py 4 2 -q
704   16
705   $ python prog.py 4 2 -v
706   4 to the power 2 equals 16
707   $ python prog.py 4 2 -vq
708   usage: prog.py [-h] [-v | -q] x y
709   prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
710   $ python prog.py 4 2 -v --quiet
711   usage: prog.py [-h] [-v | -q] x y
712   prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
713
714That should be easy to follow. I've added that last output so you can see the
715sort of flexibility you get, i.e. mixing long form options with short form
716ones.
717
718Before we conclude, you probably want to tell your users the main purpose of
719your program, just in case they don't know::
720
721   import argparse
722
723   parser = argparse.ArgumentParser(description="calculate X to the power of Y")
724   group = parser.add_mutually_exclusive_group()
725   group.add_argument("-v", "--verbose", action="store_true")
726   group.add_argument("-q", "--quiet", action="store_true")
727   parser.add_argument("x", type=int, help="the base")
728   parser.add_argument("y", type=int, help="the exponent")
729   args = parser.parse_args()
730   answer = args.x**args.y
731
732   if args.quiet:
733       print answer
734   elif args.verbose:
735       print "{} to the power {} equals {}".format(args.x, args.y, answer)
736   else:
737       print "{}^{} == {}".format(args.x, args.y, answer)
738
739Note that slight difference in the usage text. Note the ``[-v | -q]``,
740which tells us that we can either use ``-v`` or ``-q``,
741but not both at the same time:
742
743.. code-block:: sh
744
745   $ python prog.py --help
746   usage: prog.py [-h] [-v | -q] x y
747
748   calculate X to the power of Y
749
750   positional arguments:
751     x              the base
752     y              the exponent
753
754   optional arguments:
755     -h, --help     show this help message and exit
756     -v, --verbose
757     -q, --quiet
758
759
760Conclusion
761==========
762
763The :mod:`argparse` module offers a lot more than shown here.
764Its docs are quite detailed and thorough, and full of examples.
765Having gone through this tutorial, you should easily digest them
766without feeling overwhelmed.
767