The python package ‘argparse’ is a highly versatile and customizable command line parser.

I’m going to show you a handful of examples that should cover most of your use cases, if not you can reference the full ‘argparse’ documentation here.

Come on – let’s take a look.

Prerequisites

Although you could apply the examples we cover here to just a single python script we are going to flex our Python skill by wrapping up our examples in python packages, and implementing python console commands. This makes it easier on your users, and in this case easier for you – you can access the examples quite quickly.

You can catch up on Python packaging here, and Python callable console commands here.

Play Along: Install ‘pkgexampleargparse’

If you want to play along with me but only want to just run the commands as you read, that is fine.
‘pkgexampleargparse’ is now live on pypi.org ,

and can be installed on your ubuntu system with the following command.

ubuntu@goodboy:~$ python3 -m pip install pkgexampleargparse
Defaulting to user installation because normal site-packages is not writeable
Collecting pkgexampleargparse
  Downloading pkgexampleargparse-0.0.2-py3-none-any.whl (4.2 kB)
Installing collected packages: pkgexampleargparse
Successfully installed pkgexampleargparse-0.0.2

Play Along: Download ‘pkgexampleargparse’

If you want to play along, but also inspect or change the code you can clone the package code from the following github repo and open it in your favorite development environment.


https://github.com/RexBytes/pkgexampleargparse
0 forks.
0 stars.
0 open issues.

Recent commits:

Step 1: Clone The ‘pkgexampleargparse’ Repository

git clone [email protected]:RexBytes/pkgexampleargparse.git

Once cloned, you should have the following package directory structure.

ubuntu@goodboy:~$ tree -a pkgexampleargparse/
pkgexampleargparse/
├── .gitignore
├── LICENCE
├── pyproject.toml
├── README.md
├── setup.py
└── src
    └── pkgexampleargparse
        ├── __init__.py
        └── my_argparse_module.py

2 directories, 7 files

The file ‘my_argparse_module.py’ is the python module containing all of the examples we are about to run through.

Step 2: Confirm The Console Entries

We are going to run all of our example as console commands, more on console commands here.

Lets confirm that our commands, and the entry point functions are noted at the end of the ‘pyproject.toml’ file.

[project.scripts]
rexconcat = "pkgexampleargparse:my_argparse_module.my_string_list"
rexadd  = "pkgexampleargparse:my_argparse_module.my_int_list"
rexhello = "pkgexampleargparse:my_argparse_module.my_store"
rexanimal = "pkgexampleargparse:my_argparse_module.my_store_const"
rexbool = "pkgexampleargparse:my_argparse_module.my_bool"
rexgroups = "pkgexampleargparse:my_argparse_module.my_groups"
rexsub = "pkgexampleargparse:my_argparse_module.my_subparser"

If you check the end of the ‘pyproject.toml’ file, you should see 7 command names on the left and the functions referenced on the right.

Step3: Install Package Interactively

For a smoother development experience we are going to install this package interactively, more on interactive python package installs here.

You can install this package interactively if you run the following command from your package root directory.

python3 -m pip install --no-build-isolation -e .

Your output should approximately match the following.

ubuntu@goodboy:~/pkgexampleargparse$ python3 -m pip install --no-build-isolation -e .
Defaulting to user installation because normal site-packages is not writeable
Obtaining file:///home/ubuntu/pkgexampleargparse
  Checking if build backend supports build_editable ... done
  Preparing editable metadata (pyproject.toml) ... done
Building wheels for collected packages: pkgexampleargparse
Successfully installed pkgexampleargparse-0.0.2
ubuntu@goodboy:~/myrepos/rex/pkgexampleargparse$

I have left out a lot of output though to save space here.

You should now be able to modify the examples, and see your modifications straight away.

Common Argument Parsing Examples

If you open up ‘my_argparse_module.py’, you will see at the top of the file the following import statement.

import argparse

This imports the argparse package.

The rest of the ‘my_argparse_module.py’ contains our example functions.

We apply one type of argument per example, but in your application you can mix and match as many argument types as you like… and implement more complex argument logic handling.

Example 1: String List

We are going to write a function that concatenates a list of strings.

We setup our parser on lines 2 & 3.
On line 2, we create our parser object and name it ‘my_string_list_parser’ and give it a description.

On line 3, we add our first argument. We name the argument ‘input_strings‘, we give it a metavar value of ‘S‘ which will be used in the help output, we set the type as ‘str‘ and set the number of arguments to unlimited nargs=’+’, and finally give our argument a help description.

On line 5, we parse any arguments inputted by a user and store them in the ‘my_args‘ variable.

On lines 7-8, we implement the functionality.

def my_string_list():
    my_string_list_parser = argparse.ArgumentParser(description="My 'str list' Argparse Script")
    my_string_list_parser.add_argument('input_strings',metavar='S',type=str, nargs='+', help="A list of strings you want to concatinate."  )

    my_args = my_string_list_parser.parse_args()

    if my_args.input_strings:
        return ''.join(my_args.input_strings)

This example function is referenced by the following [project.script] entry.

rexconcat = "pkgexampleargparse:my_argparse_module.my_string_list"

Lets see how it looks on the command line. You should be able to play along.

Open up your terminal and lets call the help function.

ubuntu@goodboy:~$ rexconcat --help
usage: rexconcat [-h] S [S ...]

My 'str list' Argparse Script

positional arguments:
  S           A list of strings you want to concatinate.

options:
  -h, --help  show this help message and exit

Lets actually run the function with correct input.

ubuntu@goodboy:~$ rexconcat one banana tree
onebananatree
ubuntu@goodboy:~$

Congratulations on your first argparse argument.

Example 2: Integer List

In a similar entrypoint function, we are going to add a list of 2 integers.

On line 2-3, we setup our parser and our argument in the same way. Here though we define the type as type=int, and also restring the number of arguments we will accept with nargs=2 .

On line 5, we again parse in our users arguments.

On lines 7-10, we implement the functionality.

def my_int_list():
    my_int_list_parser = argparse.ArgumentParser(description="My 'int list' Argparse Script")
    my_int_list_parser.add_argument('input_numbers',metavar='N',type=int, nargs=2, help="Two numbers you want to add"  )
    
    my_args = my_int_list_parser.parse_args()

    if my_args.input_numbers:
        my_numbers=my_args.input_numbers 
        my_sum=my_numbers[0]+my_numbers[1] 
        print(my_sum)

This example function is referenced by the following [project.script] entry.

rexadd  = "pkgexampleargparse:my_argparse_module.my_int_list"

Lets check the help output.

ubuntu@goodboy:~$ rexadd --help
usage: rexadd [-h] N N

My 'int list' Argparse Script

positional arguments:
  N           Two numbers you want to add

options:
  -h, --help  show this help message and exit
ubuntu@goodboy:~$

Lets see it in action.

ubuntu@goodboy:~$ rexadd 5 10
15
ubuntu@goodboy:~$

Example 3: Default Store

We are able to assign values to argument variables.
The default behavior is to take the user input, and set the name of a variable to that value.

On lines 2-3 we setup our parser, and our argument.
This time our argument has a short name ‘-l‘, and a long name ‘–my-language‘. We also give the users 3 choices, and set a default value to the argument.

One thing to note, even though your argument is named ‘–my-language’, your python code can only access it’s value if you reference it as ‘my_language‘ .

On line 7-10 we implement the functionality, and you can see the name of the variable ‘my_language‘.

def my_store():
    my_store_parser = argparse.ArgumentParser(description="My 'Store' Argparse Script")
    my_store_parser.add_argument('-l','--my-language', choices=['French','English','German'],help="Choose your language. ",default='English')

    my_args = my_store_parser.parse_args()

    if type(my_args.my_language) is str:
        if (my_args.my_language).lower() == "french":
            print("Bonjour le monde!")
        elif (my_args.my_language).lower() == "english":
            print("Hello World!")
        elif (my_args.my_language).lower() == "german":
            print("Hallo Welt!")
        else:
            print("Only French, English and German languages are supported.") 

This example function is referenced by the following [project.script] entry.

rexhello = "pkgexampleargparse:my_argparse_module.my_store"

Lets run the help on this function.

ubuntu@goodboy:~$ rexhello --help
usage: rexhello [-h] [-l {French,English,German}]

My 'Store' Argparse Script

options:
  -h, --help            show this help message and exit
  -l {French,English,German}, --my-language {French,English,German}
                        Choose your language.

I’m going to run this function in German.

ubuntu@goodboy:~$ rexhello --my-language German
Hallo Welt!
ubuntu@goodboy:~$

Example 4: Store Constant

We can also store pre-defined constants.

On lines 2-4 we setup our parser, and two “store arguments” but we override the default behavior by setting action=’store_const’. We can now define our own constants, here I set ‘Meow’ for our cat argument, and ‘Woof Woof’ for our dog argument.

On line 6-10 we implement the functionality. When a user provides a cat argument, we set our own constant as mentioned above and output some strings.

def my_store_const():
    my_store_const_parser = argparse.ArgumentParser(description="My 'Store Const' Argparse Script")
    my_store_const_parser.add_argument('-c','--cat', action='store_const', const='Meow', help='Set cat animal sound.')
    my_store_const_parser.add_argument('-d','--dog', action='store_const', const='Woof Woof', help='Set dog animal sound.')
    
    my_args = my_store_const_parser.parse_args()
    if my_args.cat is not None:
        print(f"Did you just hear something go \"{my_args.cat}\" !!!!!")
    if my_args.dog is not None:
        print(f"Did you just hear something go \"{my_args.dog}\" !!!!!")

This example function is referenced by the following [project.script] entry.

rexanimal = "pkgexampleargparse:my_argparse_module.my_store_const"

Lets check the help for this function.

ubuntu@goodboy:~$ rexanimal --help
usage: rexanimal [-h] [-c] [-d]

My 'Store Const' Argparse Script

options:
  -h, --help  show this help message and exit
  -c, --cat   Set cat animal sound.
  -d, --dog   Set dog animal sound.
ubuntu@goodboy:~$

And lets run it.

ubuntu@goodboy:~$ rexanimal --cat
Did you just hear something go "Meow" !!!!!
ubuntu@goodboy:~$ rexanimal --dog
Did you just hear something go "Woof Woof" !!!!!
ubuntu@goodboy:~$

Example 5: Store Bool

Store Bool‘ is a special case of ‘Store Const

On line 2-3, we setup our parser and our bool argument. Here, we are just using the long name for our argument, and setting the action to action=’store_true’. If the argument is present, it set our constant equal to True. If the argument is not present, it sets our constant to False. The reverse is true if you set action=’store_false’

On line 5, we parse our user arguments.

On line 7, we have a simple implementation and output the contents of our constant.

def my_bool():
    my_bool_parser = argparse.ArgumentParser(description="My Bool Argparse Script")
    my_bool_parser.add_argument('--is-hot', action='store_true')
    
    my_args = my_bool_parser.parse_args()

    print(my_args.is_hot)

This example function is referenced by the following [project.script] entry.

rexbool = "pkgexampleargparse:my_argparse_module.my_bool"

Lets run the help.

ubuntu@goodboy:~$ rexbool --help
usage: rexbool [-h] [--is-hot]

My Bool Argparse Script

options:
  -h, --help  show this help message and exit
  --is-hot
ubuntu@goodboy:~$

Lets see the command in action.

ubuntu@goodboy:~$ rexbool --is-hot
True
ubuntu@goodboy:~$ rexbool
False
ubuntu@goodboy:~$

As expected you see that ‘True’ is returned if you provide the argument, and ‘False’ if not.

Argument Grouping

Group Example 1:

Solely for the benefit of structuring your help output, argparse has an ‘.add_argument_group(<groupname>,<description>)’ function. You can create a group parser object, and add arguments to that group parser in the same way as we have been doing to the main parser.

Line 4, and 9 demonstrates this.

Line 12, here you can see that all group arguments are parsed through the main group parser defined on line 2 and are used in your implementations as before.

def my_groups():
    main_group_parser = argparse.ArgumentParser(description="My 'Group Argument' Argparse Script",prog='my_program_name',add_help=True)

    group1 = main_group_parser.add_argument_group('group1', 'My group 1 description!')
    group1.add_argument('-c','--cat-said', help="What did the cats say?")



    group2 = main_group_parser.add_argument_group('group2', 'My group 2 description!')
    group2.add_argument('-f','--fox-said', help='What did the fox say?')


    my_args=main_group_parser.parse_args()

    if my_args.cat_said is not None:
        print(f"The cat said \"{my_args.cat_said}\" !!")


    if my_args.fox_said is not None:
        print(f"The fox said \"{my_args.fox_said}\" !!")
rexgroups = "pkgexampleargparse:my_argparse_module.my_groups"

If you look at the group help output, you should see two separate help groups. This should help you structure your more complex python code.

ubuntu@goodboy:~$ rexgroups --help
usage: my_program_name [-h] [-c CAT_SAID] [-f FOX_SAID]

My 'Group Argument' Argparse Script

options:
  -h, --help            show this help message and exit

group1:
  My group 1 description!

  -c CAT_SAID, --cat-said CAT_SAID
                        What did the cats say?

group2:
  My group 2 description!

  -f FOX_SAID, --fox-said FOX_SAID
                        What did the fox say?
ubuntu@goodboy:~$

Let’s run the code.

ubuntu@goodboy:~$ rexgroups --cat-said Meow
The cat said "Meow" !!
ubuntu@goodboy:~$ rexgroups --fox-said "tchoff-tchoff-tchoffo-tchoffo-tchoff!"
The fox said "tchoff-tchoff-tchoffo-tchoffo-tchoff!" !!
ubuntu@goodboy:~$

As you can see, we run and handle the arguments in the same way.

Subcommands

Now this one is interesting. Many command line applications have subcommands.

Take a look at git,

ubuntu@goodboy:~$ git commit
ubuntu@goodboy:~$ git status
ubuntu@goodboy:~$ git push
ubuntu@goodboy:~$ git clone

You have the first command ‘git’, and all of its other subcommands.

Let me show you how to do this in argparse.

Subcommand Example 1:

On line 3-4, we define our top level parser as usual and can also add arguments to the top level.

On line 6 we create a subparser object that will contain all of our subcommand parsers.

A subparser is treated in exactly the same way as a top level parser.

On lines 8 and 11 we create our subparsers, and add arguments from the above examples.

On line 14 we parse in all of the arguments through the top level parser, you access all of the subcommand arguments through the same variable.

On line 16-29 we implement the functionality, watch out, as commands are run only if you say “Simon Says”.

def my_subparser():

    my_toplevel_parser = argparse.ArgumentParser()
    my_toplevel_parser.add_argument('--simon-says', action='store_true', help='If this switch isn\'t given, commands won\'t work.')

    subparsers = my_toplevel_parser.add_subparsers(help='Available subcommands')

    parser_a = subparsers.add_parser('animalsaid',help='Tell us what the animal said, supply a string.')
    parser_a.add_argument('-c','--cat-said', help='What did the cat say?')

    parser_b = subparsers.add_parser('add2numbers',help='Use this command to add two integers.')
    parser_b.add_argument('input_numbers',metavar='N',type=int, nargs=2, help="Two numbers you want to add"  )

    my_args=my_toplevel_parser.parse_args()

    if my_args.simon_says == True:

        if 'cat_said' in my_args:
            if my_args.cat_said is not None:
                print(f"The cat said \"{my_args.cat_said}\" ")

        if 'input_numbers' in my_args:
            if my_args.input_numbers is not None:
                my_numbers=my_args.input_numbers 
                my_sum=my_numbers[0]+my_numbers[1] 
                print(my_sum)
    else:

        print("Ah ah ah... you didn't say Simon Says.")

This example function is referenced by the following [project.script] entry.

rexsub = "pkgexampleargparse:my_argparse_module.my_subparser"

Lets take a look at the help. Notice that you can ask for help for the top level command, and both subcommands.

ubuntu@goodboy:~$ rexsub --help                                              <-- Top Level Command Help
usage: rexsub [-h] [--simon-says] {animalsaid,add2numbers} ...

positional arguments:
  {animalsaid,add2numbers}
                        Available subcommands
    animalsaid          Tell us what the animal said, supply a string.
    add2numbers         Use this command to add two integers.

options:
  -h, --help            show this help message and exit
  --simon-says          If this switch isn't given, commands won't work.
ubuntu@goodboy:~$
ubuntu@goodboy:~$
ubuntu@goodboy:~$
ubuntu@goodboy:~$ rexsub animalsaid --help                                   <-- Subcommand Help
usage: rexsub animalsaid [-h] [-c CAT_SAID]

options:
  -h, --help            show this help message and exit
  -c CAT_SAID, --cat-said CAT_SAID
                        What did the cat say?
ubuntu@goodboy:~$
ubuntu@goodboy:~$
ubuntu@goodboy:~$
ubuntu@goodboy:~$ rexsub add2numbers --help                                  <-- Subcommand Help
usage: rexsub add2numbers [-h] N N

positional arguments:
  N           Two numbers you want to multiply

options:
  -h, --help  show this help message and exit
ubuntu@goodboy:~$

Lets run some examples.

ubuntu@goodboy:~$ rexsub add2numbers 5 10
Ah ah ah... you didn't say Simon Says.
ubuntu@goodboy:~$ rexsub --simon-says add2numbers 5 10
15
ubuntu@goodboy:~$
ubuntu@goodboy:~$ rexsub animalsaid --cat-said "Meaow"
Ah ah ah... you didn't say Simon Says.
ubuntu@goodboy:~$ rexsub --simon-says animalsaid --cat-said "Meaow"
The cat said "Meaow"
ubuntu@goodboy:~$

As you can see, if you don’t say “Simon Says” at the top command level, the subcommands will not execute.

Subcommand Example 2:

Subcommands logic can get a little complicated, I prefer to use decorators. I have re-written the if-then-else handling of the above code as follows.
Functionally they are the same, and have kept the decorator version in the ‘pkgexampleargparse’

def my_subparser():

    def subcommand(func):
        def wrapper(*args,**kwargs):
            if my_args.simon_says == True:
                return func(*args,**kwargs)
            else:
                print("Ah ah ah... you didn't say Simon Says.")
        return wrapper
        

    @subcommand
    def animalsaid():
        if my_args.cat_said is not None:
            print(f"The cat said \"{my_args.cat_said}\" ")

    @subcommand
    def add2numbers():
         if my_args.input_numbers is not None:
                my_numbers=my_args.input_numbers 
                my_sum=my_numbers[0]+my_numbers[1] 
                print(my_sum)

    my_toplevel_parser = argparse.ArgumentParser()
    my_toplevel_parser.add_argument('--simon-says', action='store_true', help='If this switch isn\'t given, commands won\'t work.')

    subparsers = my_toplevel_parser.add_subparsers(help='Available subcommands')

    parser_a = subparsers.add_parser('animalsaid',help='Tell us what the animal said, supply a string.')
    parser_a.add_argument('-c','--cat-said', help='What did the cat say?')
    parser_a.set_defaults(func=animalsaid)

    parser_b = subparsers.add_parser('add2numbers',help='Use this command to add two integers.')
    parser_b.add_argument('input_numbers',metavar='N',type=int, nargs=2, help="Two numbers you want to multiply"  )
    parser_b.set_defaults(func=add2numbers)

    my_args=my_toplevel_parser.parse_args()

    my_args.func()
One thought on “Python Parsing Command Line Arguments With argparse”

Leave a Reply