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