Creating CLI Commands using Argparse in Python

sachingeek

Sachin

Posted on March 31, 2024

Creating CLI Commands using Argparse in Python

Python has a rich and versatile collection of standard libraries, making it one of the better programming languages, so it needs to cover all the areas of programming.

If developers want to write the scripts for the command line using Python, then there must be some libraries that allow them to write command line scripts conveniently. Python has a library called argparse that helps to create exemplary command-line interfaces for the command-line scripts.

In this article, we'll be going to learn:

  • What is argparse in Python

  • How to create a basic CLI in Python using argparse

  • What are the advanced features of Python argparse

What is CLI

A command line interface, short for CLI, is a medium or type of interface that allows us to interact with a command line script. Python has many libraries that allow us to write the command line interface for our scripts. We'll use a library called argparse to create a CLI in Python.

It is a standard way to create a CLI in Python, and argparse came as a replacement for the modules like optparse and getopt because they lacked some significant features.

Getting to know CLI

Before we proceed any further, we need to know how the command line interface works, so open up your terminal on your computer and execute a command 'python' to start using Python commands in your command line.

>python
....
Python 3.10.5 (tags/v3.10.5:f377153, Jun  6 2022, 16:14:13) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print("Hello Geeks!")
Hello Geeks!
>>> 3 % 6
3
>>> sum([4, 19, 111])
134
Enter fullscreen mode Exit fullscreen mode

Here we can execute the Python commands directly in our CLI. Fortunately, we don't need any Python interpreter to get started. Still, we can add an option(type of argument) with the argument to get the extra information.

>python --version
....
Python 3.10.5

>python -q
....
>>> print("Python has started without prompting copyright and version messages.")
Python has started without prompting copyright and version messages.
Enter fullscreen mode Exit fullscreen mode

Here we obtained the version of Python that we are currently using by just adding the --version option to the python argument, and in the second command, we used the -q option to start the Python interpreter without prompting the version and copyright messages that it usually shows on startup.

To understand arguments, options, and parameters, consider the following example:

>dir /d /r D:\SACHIN\Pycharm\cli_flask
Enter fullscreen mode Exit fullscreen mode
  • dir: The name of the command we are executing

  • /d: An option to display all directories in the current path

  • /r: An option to display the read-only files

  • D:\SACHIN\Pycharm\cli_flask: A parameter to list the directories in the specified path

To explain precisely,

An argument is a command that we want to execute.

An option is a part of an argument or type of argument used to modify the behavior of the command line.

A parameter is a type of argument that provides additional information to the command.

Creating a basic command using argparse

We can create an essential command for CLI in a few steps using argparse. Let's understand the measures included in the process of making the command.

  • Importing the argparse because it's a Python library

  • Creating the parser

  • Adding the positional and optional arguments to the parser

  • Executing the parser using the parse_args()

Let's assume we have a file named command.py in which we write the basic command to get the factorial of the integer specified in the command line interface or CLI.

# Importing argparse library
import argparse

from math import factorial

# Creating the parser
parser = argparse.ArgumentParser(description='Get the factorial of the integer.')

# Adding the argument
parser.add_argument('Factorial',
                    metavar='integer',
                    type=int,
                    help='factorial of the integer')

# Executing the parser using parse_args() method
args = parser.parse_args()

fact = args.Factorial
print(factorial(fact))
Enter fullscreen mode Exit fullscreen mode

We've coded our first-ever command for CLI and now let's understand our code. We can divide our code into four parts.

First, we imported the argparse library and then created the parser using the ArgumentParser() method in which we passed the detail argument to specify the detail of our command.

Next, we added the argument to the parser using the add_argument method, which holds the necessary information passed into the arguments inside the method. Finally, we executed our parser using the parse_args() method.

If we run our command in the CLI without specifying any value, then we will get an error and a usage message.

>python command.py  
usage: command.py [-h] integer
command.py: error: the following arguments are required: integer
Enter fullscreen mode Exit fullscreen mode

The program detected that we needed a positional argument (integer) to complete the execution, but the execution was interrupted due to the absence of the positional argument.

We can see that our command accepts an optional -h flag.

>python command.py -h
usage: command.py [-h] integer

Get the factorial of the integer.

positional arguments:
  integer     factorial of the integer

options:
  -h, --help  show this help message and exit
Enter fullscreen mode Exit fullscreen mode

If we execute our command with the positional argument it needs, we'll get the desired result.

>python command.py 6 
720
Enter fullscreen mode Exit fullscreen mode

Advanced usage of argparse

We learned the basic usage of the argparse library, and now we can create an essential command for CLI. However, this is not it, we can do many more things using this library. We'll see some advanced usage of the argparse library.

Display custom help message

The argparse library generates usage help if not provided, but we can customize the help message using the usage keyword.

parser = argparse.ArgumentParser(
    usage='command.py [options] integer',
    description='Get the factorial of the integer.')
Enter fullscreen mode Exit fullscreen mode

Now we can see the different usage messages if we execute the program.

>python command.py
usage: factorial [options] integer
factorial: error: the following arguments are required: integer
Enter fullscreen mode Exit fullscreen mode

Setting the program name

In the previous section, we saw the Python script name when we executed the program in the CLI because the library uses the sys.argv[0] to set the program's name. However, we can specify the program name using the prog keyword.

parser = argparse.ArgumentParser(
    prog='factorial',
    description='Get the factorial of the integer.')
Enter fullscreen mode Exit fullscreen mode

We will now see our specified name, factorial, of the program in the CLI instead of the Python script name.

>python command.py
usage: factorial [-h] integer
factorial: error: the following arguments are required: integer
Enter fullscreen mode Exit fullscreen mode

Displaying text before and after the arguments

We can customize the text we want to display before and after in the help text by using the following keywords.

  • description: for the text shown before the help text

  • epilog: for the text shown after the help text

We have already seen the use of description. This time we'll use the epilog to display the text after the help text.

parser = argparse.ArgumentParser(
    description='Get the factorial of the integer.',
    epilog='Have you understood the process? ')
Enter fullscreen mode Exit fullscreen mode

We will see the customized message after the help text.

>python command.py -h
usage: command.py [-h] integer

Get the factorial of the integer.

positional arguments:
  integer     factorial of the integer

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

Have you understood the process?
Enter fullscreen mode Exit fullscreen mode

Customizing prefix character

The optional arguments in the CLI command are generally prefixed with (-), a standard prefix char. The argparse library has a feature that allows us to customize the prefix chars.

The prefix_chars keyword lets us customize the prefix character while defining the parser.

parser = argparse.ArgumentParser(
    description='Get the factorial of the integer.',
    prefix_chars='$')
Enter fullscreen mode Exit fullscreen mode

Now, in the output, we won't see (-) as the prefix char for the optional argument instead, we will see the ($) as the prefix char.

>python command.py   
usage: command.py [$h] integer
command.py: error: the following arguments are required: integer
Enter fullscreen mode Exit fullscreen mode

Now our program does not support the -h flag but the $h flag. The help text has also changed accordingly.

Enable and disable help

Python argparse library automatically generates the help text without having to code anything. However, sometimes we wanted to disable the feature. We can add the add_help keyword when creating the parser.

parser = argparse.ArgumentParser(
    description='Get the factorial of the integer.',
    add_help=False)
Enter fullscreen mode Exit fullscreen mode

We've added the add_help keyword in the above code and set its value to False. It ensures that the program does not accept the -h flag anymore.

>python command.py
usage: command.py integer
command.py: error: the following arguments are required: integer
Enter fullscreen mode Exit fullscreen mode

Allowing and disallowing abbreviation

One of the features the Python argparse library provides is the ability to handle abbreviations. Consider the following example that prints the square of the specified integer.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--square', action='store', type=int)
parser.add_argument('--sum', action='store', type=int)

args = parser.parse_args()
print(args.square**2)
Enter fullscreen mode Exit fullscreen mode

We can shorten the optional argument until the abbreviation leads to the wrong interpretation.

>python abbreviation.py --square 4 
16

>python abbreviation.py --squar 4  
16

>python abbreviation.py --squa 4  
16

>python abbreviation.py --squ 4  
16

>python abbreviation.py --sq 4  
16
Enter fullscreen mode Exit fullscreen mode

We can shorten the optional argument until --sq 4. What happens if we execute the program specifying --s 4? It might lead to an error because argparse doesn't know whether we want to specify 4 to the --square or the --sum argument.

>python abbreviation.py --s 4   
usage: abbreviation.py [-h] [--square SQUARE] [--sum SUM]
abbreviation.py: error: ambiguous option: --s could match --square, --sum
Enter fullscreen mode Exit fullscreen mode

However, we can force users to specify the full name of the option by disabling the feature by adding the allow_abbrev while creating the parser.

import argparse

parser = argparse.ArgumentParser(allow_abbrev=False)
parser.add_argument('--square', action='store', type=int)
parser.add_argument('--sum', action='store', type=int)

args = parser.parse_args()

print(args.square**2)
Enter fullscreen mode Exit fullscreen mode

Now, if we try to execute the program using an abbreviation, the program will throw an error.

>python abbreviation.py --squa 4  
usage: abbreviation.py [-h] [--square SQUARE]
abbreviation.py: error: unrecognized arguments: --squa 4
Enter fullscreen mode Exit fullscreen mode

Setting the name or flag of the arguments

There are two types of arguments that we can use in our command line interface:

Positional arguments

In the previous examples, we've already seen the positional arguments. In the example above, Factorial was the positional argument, and our program couldn't work without it.

Positional arguments are the types of argument that we use in command to perform some operation. They are called positional arguments because their position defines their function.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('Square', type=int, help='square of the integer')

args = parser.parse_args()

print(args.Square**2)
Enter fullscreen mode Exit fullscreen mode

Here, Square is the positional argument, and when we specify an integer, the program returns the square of that integer. By default, the positional argument is treated as a String, so we used the type keyword and set its value to int to typecast the string into the integer.

Optional arguments

The optional arguments are used to perform the additional tasks, and when they are used, they can modify the command's behavior at runtime.

For example, if we look at the ls command that lists the files in a current directory and if we use the -l argument, which is an optional argument, it modifies the output and returns the extra information.

$ ls -l
Enter fullscreen mode Exit fullscreen mode

Optional arguments are not mandatory, and we won't get any errors if we don't specify them. They are generally prefixed with a (-) dash or (--) double dash.

import argparse
import math

parser = argparse.ArgumentParser()
parser.add_argument('-s', 
                    '--sq_root', 
                    type=int, 
                    help='square root of the integer')

args = parser.parse_args()

sqrt = args.sq_root

print(math.sqrt(sqrt))
Enter fullscreen mode Exit fullscreen mode

Output

>python op_arg.py --sq_root 9 
3.0

>python op_arg.py -s 9        
3.0
Enter fullscreen mode Exit fullscreen mode

Setting the action

When we add an argument to the command line interface, we can also define the kind of action to take when the argument is specified.

The action keyword argument specifies how the command-line arguments should be handled. Many actions are available and ready to use:

  • store: stores the argument's value. This is the default action.

  • store_const: stores a constant value when the optional arguments are specified.

  • store_true and store_false: used for storing the boolean values True and False respectively when the optional arguments are specified and stores a False and True elsewhere, respectively.

  • append: stores a list and appends each argument value to the list.

  • append_const: stores a list and appends the constant value to the list each time the option is provided.

  • count: counts the number of times the option is provided.

  • help: shows the help message and then exits.

  • version: shows the program's version information and exits.

  • extend: stores a list and extends each argument value to the list. It was added in Python v3.8.

Let's understand what these actions can do with simple examples.

We've used the action='store' in the following example, which will store the specified value.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--store', action='store')

args = parser.parse_args()
print(args.store)
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py --store 23 
23
{'store': '23'}

>python action.py --store hello
hello
{'store': 'hello'}
Enter fullscreen mode Exit fullscreen mode

The action='store_const' stores the value specified by the const keyword. We've defined the const keyword and set its value to hello.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--sc', action='store_const', const='hello')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

We just provided the --sc argument, and we got the value specified in the const keyword because the value of args.sc is now hello.

>python action.py --sc     
{'sc': 'hello'}
Enter fullscreen mode Exit fullscreen mode

The action='store_true' stores the boolean True and stores the False elsewhere when the arguments are passed. We can use action='store_false' for the opposite behavior.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--st', action='store_true')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py        
{'st': False}

>python action.py --st
{'st': True}
Enter fullscreen mode Exit fullscreen mode

The action='append' creates a list of values passed in the CLI.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--append', action='append')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py --append hello --append world
{'append': ['hello', 'world']}
Enter fullscreen mode Exit fullscreen mode

The action='append_const' is the same as append, but it appends the same constant value.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--ac', action='append_const', const='2')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py --ac --ac --ac               
{'ac': ['2', '2', '2']}
Enter fullscreen mode Exit fullscreen mode

The action='count' counts the number of times the argument is passed.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--count', action='count', default=0)

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py --count --count --count --count
{'count': 4}
Enter fullscreen mode Exit fullscreen mode

We've already seen the help message in our examples previously, which is enabled for the -h flag. The action='help' lets us use another flag for the help message.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-x', action='help')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py -x
usage: action.py [-h] [-x]

options:
  -h, --help  show this help message and exit
  -x
Enter fullscreen mode Exit fullscreen mode

The action='version' helps us to get the program's version, but it expects a version keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-z', action='version', version='1.11')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py -z
1.11
Enter fullscreen mode Exit fullscreen mode

The action='extend' extends the argument values to the list.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-e', action='extend', nargs='+')

args = parser.parse_args()
print(vars(args))
Enter fullscreen mode Exit fullscreen mode

Output

>python action.py -e 2 4 6 3 -e 0 9
{'e': ['2', '4', '6', '3', '0', '9']}
Enter fullscreen mode Exit fullscreen mode

Setting the default value

Since the optional arguments are not mandatory, they can be omitted by the user in the command line interface. In this situation, the value is generally set to None.

We can set the default value for an argument when it is not provided using the default keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-d', default=5)

args = parser.parse_args()

print(vars(args))
Enter fullscreen mode Exit fullscreen mode

We'll get the following output if we execute the program without specifying the -d option.

>python default.py     
{'d': 5}
Enter fullscreen mode Exit fullscreen mode

We didn't receive any error because option -d is set to 5.

Setting the type of the argument

By default, the input arguments are treated as a string, and we can typecast the input arguments in the desired datatype using the type keyword. We've already seen examples where we used the type keyword.

import argparse
import math

parser = argparse.ArgumentParser()
parser.add_argument('-f', type=int,)

args = parser.parse_args()

print(math.factorial(args.f))
Enter fullscreen mode Exit fullscreen mode

type=int will ensure that the argument's value must be an integer instead of a string.

>python type.py -f 2
2
Enter fullscreen mode Exit fullscreen mode

The value of the argument is checked at the runtime. If there is any datatype other than the integer provided in the command line, then the program will throw an error.

>python type.py -f a 
usage: type.py [-h] [-f F]
type.py: error: argument -f: invalid int value: 'a'
Enter fullscreen mode Exit fullscreen mode

The error clearly states that the value a is an invalid integer, and we need to pass an integer instead of a string.

Making the argument to be required

The user can omit the optional arguments. However, we can force the user to specify the value for an optional argument by making the argument to be required by using the required keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-d', required=True)

args = parser.parse_args()

print(vars(args))
Enter fullscreen mode Exit fullscreen mode

We used the required keyword and set its value to True, which forces the user to specify the value for the argument.

>python required.py
usage: required.py [-h] -d D
required.py: error: the following arguments are required: -d
Enter fullscreen mode Exit fullscreen mode

Note: It is a bad practice to make an optional argument to be required by the user because the name itself depicts that it is optional, and the user wouldn't expect to set a value for the argument.

Setting the number of values the argument can take

Usually, we specify the single value to the argument, which is the default behavior. We can change this default behavior by specifying the number of values an argument can consume using the nargs keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--value', type=int, nargs=2)

args = parser.parse_args()

print(args.value)
Enter fullscreen mode Exit fullscreen mode

The program will accept only two values, not more or less than that.

>python nargs.py --value 1
usage: nargs.py [-h] [--value VALUE VALUE]
nargs.py: error: argument --value: expected 2 arguments

>python nargs.py --value 1 2
[1, 2]

>python nargs.py --value 1 2 34
usage: nargs.py [-h] [--value VALUE VALUE]
nargs.py: error: unrecognized arguments: 34
Enter fullscreen mode Exit fullscreen mode

As we can see, when we provided a single and more than two values, the program threw an error, but when we provided the two values, the program returned the list containing the two values.

Instead of using any integer, the nargs keyword also accepts the following:

  • ?: a single value will be consumed, which can be optional

  • *: an extensible number of values, which will be gathered into a list

  • +: much like *, but it requires at least one value

  • argparse.REMAINDER: all the values that are remaining in the command line

In the following example, the positional argument value accepts a single value. If the value is not provided, it returns the value set in the default keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('value',
                    nargs='?',
                    default='This is a default value.')

args = parser.parse_args()

print(args.value)
Enter fullscreen mode Exit fullscreen mode

We can now set the specific value for the value argument. If the value is not provided, it will prompt the default value in the command line.

>python nargs.py 2
2

>python nargs.py          
This is a default value.
Enter fullscreen mode Exit fullscreen mode

If we wanted to provide a flexible number of values and gather them into a list, then we need to use the ***** value for the nargs keyword.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('value',
                    nargs='*',
                    default='This is a default value.')

args = parser.parse_args()

print(args.value)
Enter fullscreen mode Exit fullscreen mode

The above code allows us to set a flexible number of values, which we can see in the following output.

>python nargs.py more than one value
['more', 'than', 'one', 'value']

>python nargs.py                    
This is a default value.
Enter fullscreen mode Exit fullscreen mode

We can use the + value for the nargs keyword when we want a variable number of values, but we need to ensure that at least one value is specified.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('value',
                    nargs='+',)

args = parser.parse_args()

print(args.value)
Enter fullscreen mode Exit fullscreen mode

The above code can accept a variable number of values but make sure at least one value is specified. Otherwise, it will throw an error.

>python nargs.py needs at least one value
['needs', 'at', 'least', 'one', 'value']

>python nargs.py                         
usage: nargs.py [-h] value [value ...]
nargs.py: error: the following arguments are required: value
Enter fullscreen mode Exit fullscreen mode

As we can see, when we executed the program without any value, it threw an error, while when we provided multiple values, it returned the list containing the values.

Consider the following example, where we're using the argparse.REMAINDER value to the nargs for the remaining argument to grab all the remaining values that have been specified in the command line and put them in a list.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('value')
parser.add_argument('remaining', nargs=argparse.REMAINDER)

args = parser.parse_args()

print(f'First value: {args.value}')
print(f'Other values: {args.remaining}')
Enter fullscreen mode Exit fullscreen mode

If we execute the program, the first value will be assigned to the first argument, and the remaining will be assigned to the second argument.

>python nargs.py hey there geeks
First value: hey
Other values: ['there', 'geeks']
Enter fullscreen mode Exit fullscreen mode

Displaying an alternate name for the argument

Using the metavar keyword, we can set the name for our argument that will show in the usage message.

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-s',
                    '--square',
                    metavar='Square',)

args = parser.parse_args()

print(vars(args))
Enter fullscreen mode Exit fullscreen mode

If we execute the program with the -h flag, we can see the name Square will be assigned to the -s and --square options in the help text.

>python metavar.py -h
usage: metavar.py [-h] [-s Square]

options:
  -h, --help            show this help message and exit
  -s Square, --square Square
Enter fullscreen mode Exit fullscreen mode

Conclusion

This tutorial is a bit lengthy, but it is meant to be because it has detailed information about the argparse library in Python, allowing us to build the command-line interface.

We've covered the basic and advanced usage of the argparse with simple examples. We are now able to build our command-line interface conveniently.

Let's review what we've learned:

  • what is Python argparse library and how to use it

  • created the basic command-line interface

  • what are the advanced usage of the Python argparse library


πŸ†Other articles you might be interested in if you liked this one

βœ…Split your string into an array of words using the split() method in Python.

βœ…Map a function to each item in an iterable using the map() function.

βœ…Serialize and deserialize Python objects using the pickle module.

βœ…Why if __name__ == β€˜__main__’ is used in Python programs?

βœ…Create a WebSocket server and client in Python.

βœ…Upload and display images on the frontend using Flask.


That's all for now

Keep Coding✌✌

πŸ’– πŸ’ͺ πŸ™… 🚩
sachingeek
Sachin

Posted on March 31, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related