• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _argparse-tutorial:
2
3*****************
4Argparse Tutorial
5*****************
6
7:author: Tshepang Mbambo
8
9.. currentmodule:: argparse
10
11This tutorial is intended to be a gentle introduction to :mod:`argparse`, the
12recommended command-line parsing module in the Python standard library.
13
14.. note::
15
16   There are two other modules that fulfill the same task, namely
17   :mod:`getopt` (an equivalent for ``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:: shell-session
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:: shell-session
83
84   $ python prog.py
85   $ python prog.py --help
86   usage: prog.py [-h]
87
88   options:
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:: shell-session
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   options:
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:`~ArgumentParser.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:`~ArgumentParser.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:: shell-session
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   options:
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:: shell-session
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:: shell-session
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:: shell-session
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   options:
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 ``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:: shell-session
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   options:
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 ``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:: shell-session
331
332   $ python prog.py -v
333   verbosity turned on
334   $ python prog.py --help
335   usage: prog.py [-h] [-v]
336
337   options:
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(f"the square of {args.square} equals {answer}")
359   else:
360       print(answer)
361
362And now the output:
363
364.. code-block:: shell-session
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(f"the square of {args.square} equals {answer}")
393   elif args.verbosity == 1:
394       print(f"{args.square}^2 == {answer}")
395   else:
396       print(answer)
397
398And the output:
399
400.. code-block:: shell-session
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(f"the square of {args.square} equals {answer}")
427   elif args.verbosity == 1:
428       print(f"{args.square}^2 == {answer}")
429   else:
430       print(answer)
431
432And the output:
433
434.. code-block:: shell-session
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   options:
446     -h, --help            show this help message and exit
447     -v, --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(f"the square of {args.square} equals {answer}")
467   elif args.verbosity == 1:
468       print(f"{args.square}^2 == {answer}")
469   else:
470       print(answer)
471
472We have introduced another action, "count",
473to count the number of occurrences of specific options.
474
475
476.. code-block:: shell-session
477
478   $ python prog.py 4
479   16
480   $ python prog.py 4 -v
481   4^2 == 16
482   $ python prog.py 4 -vv
483   the square of 4 equals 16
484   $ python prog.py 4 --verbosity --verbosity
485   the square of 4 equals 16
486   $ python prog.py 4 -v 1
487   usage: prog.py [-h] [-v] square
488   prog.py: error: unrecognized arguments: 1
489   $ python prog.py 4 -h
490   usage: prog.py [-h] [-v] square
491
492   positional arguments:
493     square           display a square of a given number
494
495   options:
496     -h, --help       show this help message and exit
497     -v, --verbosity  increase output verbosity
498   $ python prog.py 4 -vvv
499   16
500
501* Yes, it's now more of a flag (similar to ``action="store_true"``) in the
502  previous version of our script. That should explain the complaint.
503
504* It also behaves similar to "store_true" action.
505
506* Now here's a demonstration of what the "count" action gives. You've probably
507  seen this sort of usage before.
508
509* And if you don't specify the ``-v`` flag, that flag is considered to have
510  ``None`` value.
511
512* As should be expected, specifying the long form of the flag, we should get
513  the same output.
514
515* Sadly, our help output isn't very informative on the new ability our script
516  has acquired, but that can always be fixed by improving the documentation for
517  our script (e.g. via the ``help`` keyword argument).
518
519* That last output exposes a bug in our program.
520
521
522Let's fix::
523
524   import argparse
525   parser = argparse.ArgumentParser()
526   parser.add_argument("square", type=int,
527                       help="display a square of a given number")
528   parser.add_argument("-v", "--verbosity", action="count",
529                       help="increase output verbosity")
530   args = parser.parse_args()
531   answer = args.square**2
532
533   # bugfix: replace == with >=
534   if args.verbosity >= 2:
535       print(f"the square of {args.square} equals {answer}")
536   elif args.verbosity >= 1:
537       print(f"{args.square}^2 == {answer}")
538   else:
539       print(answer)
540
541And this is what it gives:
542
543.. code-block:: shell-session
544
545   $ python prog.py 4 -vvv
546   the square of 4 equals 16
547   $ python prog.py 4 -vvvv
548   the square of 4 equals 16
549   $ python prog.py 4
550   Traceback (most recent call last):
551     File "prog.py", line 11, in <module>
552       if args.verbosity >= 2:
553   TypeError: '>=' not supported between instances of 'NoneType' and 'int'
554
555
556* First output went well, and fixes the bug we had before.
557  That is, we want any value >= 2 to be as verbose as possible.
558
559* Third output not so good.
560
561Let's fix that bug::
562
563   import argparse
564   parser = argparse.ArgumentParser()
565   parser.add_argument("square", type=int,
566                       help="display a square of a given number")
567   parser.add_argument("-v", "--verbosity", action="count", default=0,
568                       help="increase output verbosity")
569   args = parser.parse_args()
570   answer = args.square**2
571   if args.verbosity >= 2:
572       print(f"the square of {args.square} equals {answer}")
573   elif args.verbosity >= 1:
574       print(f"{args.square}^2 == {answer}")
575   else:
576       print(answer)
577
578We've just introduced yet another keyword, ``default``.
579We've set it to ``0`` in order to make it comparable to the other int values.
580Remember that by default,
581if an optional argument isn't specified,
582it gets the ``None`` value, and that cannot be compared to an int value
583(hence the :exc:`TypeError` exception).
584
585And:
586
587.. code-block:: shell-session
588
589   $ python prog.py 4
590   16
591
592You can go quite far just with what we've learned so far,
593and we have only scratched the surface.
594The :mod:`argparse` module is very powerful,
595and we'll explore a bit more of it before we end this tutorial.
596
597
598Getting a little more advanced
599==============================
600
601What if we wanted to expand our tiny program to perform other powers,
602not just squares::
603
604   import argparse
605   parser = argparse.ArgumentParser()
606   parser.add_argument("x", type=int, help="the base")
607   parser.add_argument("y", type=int, help="the exponent")
608   parser.add_argument("-v", "--verbosity", action="count", default=0)
609   args = parser.parse_args()
610   answer = args.x**args.y
611   if args.verbosity >= 2:
612       print(f"{args.x} to the power {args.y} equals {answer}")
613   elif args.verbosity >= 1:
614       print(f"{args.x}^{args.y} == {answer}")
615   else:
616       print(answer)
617
618Output:
619
620.. code-block:: shell-session
621
622   $ python prog.py
623   usage: prog.py [-h] [-v] x y
624   prog.py: error: the following arguments are required: x, y
625   $ python prog.py -h
626   usage: prog.py [-h] [-v] x y
627
628   positional arguments:
629     x                the base
630     y                the exponent
631
632   options:
633     -h, --help       show this help message and exit
634     -v, --verbosity
635   $ python prog.py 4 2 -v
636   4^2 == 16
637
638
639Notice that so far we've been using verbosity level to *change* the text
640that gets displayed. The following example instead uses verbosity level
641to display *more* text instead::
642
643   import argparse
644   parser = argparse.ArgumentParser()
645   parser.add_argument("x", type=int, help="the base")
646   parser.add_argument("y", type=int, help="the exponent")
647   parser.add_argument("-v", "--verbosity", action="count", default=0)
648   args = parser.parse_args()
649   answer = args.x**args.y
650   if args.verbosity >= 2:
651       print(f"Running '{__file__}'")
652   if args.verbosity >= 1:
653       print(f"{args.x}^{args.y} == ", end="")
654   print(answer)
655
656Output:
657
658.. code-block:: shell-session
659
660   $ python prog.py 4 2
661   16
662   $ python prog.py 4 2 -v
663   4^2 == 16
664   $ python prog.py 4 2 -vv
665   Running 'prog.py'
666   4^2 == 16
667
668
669.. _specifying-ambiguous-arguments:
670
671Specifying ambiguous arguments
672------------------------------
673
674When there is ambiguity in deciding whether an argument is positional or for an
675argument, ``--`` can be used to tell :meth:`~ArgumentParser.parse_args` that
676everything after that is a positional argument::
677
678   >>> parser = argparse.ArgumentParser(prog='PROG')
679   >>> parser.add_argument('-n', nargs='+')
680   >>> parser.add_argument('args', nargs='*')
681
682   >>> # ambiguous, so parse_args assumes it's an option
683   >>> parser.parse_args(['-f'])
684   usage: PROG [-h] [-n N [N ...]] [args ...]
685   PROG: error: unrecognized arguments: -f
686
687   >>> parser.parse_args(['--', '-f'])
688   Namespace(args=['-f'], n=None)
689
690   >>> # ambiguous, so the -n option greedily accepts arguments
691   >>> parser.parse_args(['-n', '1', '2', '3'])
692   Namespace(args=[], n=['1', '2', '3'])
693
694   >>> parser.parse_args(['-n', '1', '--', '2', '3'])
695   Namespace(args=['2', '3'], n=['1'])
696
697
698Conflicting options
699-------------------
700
701So far, we have been working with two methods of an
702:class:`argparse.ArgumentParser` instance. Let's introduce a third one,
703:meth:`~ArgumentParser.add_mutually_exclusive_group`. It allows for us to specify options that
704conflict with each other. Let's also change the rest of the program so that
705the new functionality makes more sense:
706we'll introduce the ``--quiet`` option,
707which will be the opposite of the ``--verbose`` one::
708
709   import argparse
710
711   parser = argparse.ArgumentParser()
712   group = parser.add_mutually_exclusive_group()
713   group.add_argument("-v", "--verbose", action="store_true")
714   group.add_argument("-q", "--quiet", action="store_true")
715   parser.add_argument("x", type=int, help="the base")
716   parser.add_argument("y", type=int, help="the exponent")
717   args = parser.parse_args()
718   answer = args.x**args.y
719
720   if args.quiet:
721       print(answer)
722   elif args.verbose:
723       print(f"{args.x} to the power {args.y} equals {answer}")
724   else:
725       print(f"{args.x}^{args.y} == {answer}")
726
727Our program is now simpler, and we've lost some functionality for the sake of
728demonstration. Anyways, here's the output:
729
730.. code-block:: shell-session
731
732   $ python prog.py 4 2
733   4^2 == 16
734   $ python prog.py 4 2 -q
735   16
736   $ python prog.py 4 2 -v
737   4 to the power 2 equals 16
738   $ python prog.py 4 2 -vq
739   usage: prog.py [-h] [-v | -q] x y
740   prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
741   $ python prog.py 4 2 -v --quiet
742   usage: prog.py [-h] [-v | -q] x y
743   prog.py: error: argument -q/--quiet: not allowed with argument -v/--verbose
744
745That should be easy to follow. I've added that last output so you can see the
746sort of flexibility you get, i.e. mixing long form options with short form
747ones.
748
749Before we conclude, you probably want to tell your users the main purpose of
750your program, just in case they don't know::
751
752   import argparse
753
754   parser = argparse.ArgumentParser(description="calculate X to the power of Y")
755   group = parser.add_mutually_exclusive_group()
756   group.add_argument("-v", "--verbose", action="store_true")
757   group.add_argument("-q", "--quiet", action="store_true")
758   parser.add_argument("x", type=int, help="the base")
759   parser.add_argument("y", type=int, help="the exponent")
760   args = parser.parse_args()
761   answer = args.x**args.y
762
763   if args.quiet:
764       print(answer)
765   elif args.verbose:
766       print(f"{args.x} to the power {args.y} equals {answer}")
767   else:
768       print(f"{args.x}^{args.y} == {answer}")
769
770Note that slight difference in the usage text. Note the ``[-v | -q]``,
771which tells us that we can either use ``-v`` or ``-q``,
772but not both at the same time:
773
774.. code-block:: shell-session
775
776   $ python prog.py --help
777   usage: prog.py [-h] [-v | -q] x y
778
779   calculate X to the power of Y
780
781   positional arguments:
782     x              the base
783     y              the exponent
784
785   options:
786     -h, --help     show this help message and exit
787     -v, --verbose
788     -q, --quiet
789
790
791How to translate the argparse output
792====================================
793
794The output of the :mod:`argparse` module such as its help text and error
795messages are all made translatable using the :mod:`gettext` module. This
796allows applications to easily localize messages produced by
797:mod:`argparse`. See also :ref:`i18n-howto`.
798
799For instance, in this :mod:`argparse` output:
800
801.. code-block:: shell-session
802
803   $ python prog.py --help
804   usage: prog.py [-h] [-v | -q] x y
805
806   calculate X to the power of Y
807
808   positional arguments:
809     x              the base
810     y              the exponent
811
812   options:
813     -h, --help     show this help message and exit
814     -v, --verbose
815     -q, --quiet
816
817The strings ``usage:``, ``positional arguments:``, ``options:`` and
818``show this help message and exit`` are all translatable.
819
820In order to translate these strings, they must first be extracted
821into a ``.po`` file. For example, using `Babel <https://babel.pocoo.org/>`__,
822run this command:
823
824.. code-block:: shell-session
825
826  $ pybabel extract -o messages.po /usr/lib/python3.12/argparse.py
827
828This command will extract all translatable strings from the :mod:`argparse`
829module and output them into a file named ``messages.po``. This command assumes
830that your Python installation is in ``/usr/lib``.
831
832You can find out the location of the :mod:`argparse` module on your system
833using this script::
834
835   import argparse
836   print(argparse.__file__)
837
838Once the messages in the ``.po`` file are translated and the translations are
839installed using :mod:`gettext`, :mod:`argparse` will be able to display the
840translated messages.
841
842To translate your own strings in the :mod:`argparse` output, use :mod:`gettext`.
843
844Custom type converters
845======================
846
847The :mod:`argparse` module allows you to specify custom type converters for
848your command-line arguments. This allows you to modify user input before it's
849stored in the :class:`argparse.Namespace`. This can be useful when you need to
850pre-process the input before it is used in your program.
851
852When using a custom type converter, you can use any callable that takes a
853single string argument (the argument value) and returns the converted value.
854However, if you need to handle more complex scenarios, you can use a custom
855action class with the **action** parameter instead.
856
857For example, let's say you want to handle arguments with different prefixes and
858process them accordingly::
859
860   import argparse
861
862   parser = argparse.ArgumentParser(prefix_chars='-+')
863
864   parser.add_argument('-a', metavar='<value>', action='append',
865                       type=lambda x: ('-', x))
866   parser.add_argument('+a', metavar='<value>', action='append',
867                       type=lambda x: ('+', x))
868
869   args = parser.parse_args()
870   print(args)
871
872Output:
873
874.. code-block:: shell-session
875
876   $ python prog.py -a value1 +a value2
877   Namespace(a=[('-', 'value1'), ('+', 'value2')])
878
879In this example, we:
880
881* Created a parser with custom prefix characters using the ``prefix_chars``
882  parameter.
883
884* Defined two arguments, ``-a`` and ``+a``, which used the ``type`` parameter to
885  create custom type converters to store the value in a tuple with the prefix.
886
887Without the custom type converters, the arguments would have treated the ``-a``
888and ``+a`` as the same argument, which would have been undesirable. By using custom
889type converters, we were able to differentiate between the two arguments.
890
891Conclusion
892==========
893
894The :mod:`argparse` module offers a lot more than shown here.
895Its docs are quite detailed and thorough, and full of examples.
896Having gone through this tutorial, you should easily digest them
897without feeling overwhelmed.
898