In this lesson, we will show you how to create your own command line interface tool (CLI)
using Python using the argparse
library. Primarily this means program argument processing.
... is one of ways how to interact with or control a program (not only Python scripts!) as a user - interface with it from inside the computer itself where it is installed (not over the internet). That user can be you as a creator of code and someone else you give access to it.
In the testing lesson we have shown that sometimes you need to call a Python program independently with different arguments in order to run computations with different values.
Letting the tester or user pass these arguments from command line (which means not manually editing them inside the Python script) is a great option.
The behavior of a program usually is varying - it depends on the instructions you give to it as arguments.
If you want to know what arguments does existing program allow, the argument to use is help. This works for most of programs on your computer (if their author created a help page). Also usually there is a -help
or --help
command line argument which also shows the expected usage of a tool to any user.
As an example of a tool which works on both Linux and Windows mostly the same way, you can take our beloved git.
Try running this in your terminal:
git --help
and for any subcommand as well:
git log --help
Now that you know that programs usually accept arguments and they are documented in help
, you can start using git
in many ways.
For example you can heavily customize output of git log
in some existing git repository:
git log --oneline --graph --decorate --cherry-mark --boundary
Note about "raw" command line argument handling
In order to read the command line arguments, we can use the sys.argv
variable, which gives us a list of strings, one for each passed argument:
# arguments.py
import sys
for arg in sys.argv:
print(arg)
When we execute this program with the passed in arguments, we can see them printed out. However, this is not very convenient when we want to build actual CLI programs with options and arguments. But there are good tools we can use instead!
How can we create a CLI in Python? Today, we will show usage of a argparse
tool. It is a part of the standard library, so you do not need to install anything extra.
You can find the official documentation here: argparse
And a quite handy tutorial going through most of functionalities, you could ever encounter: argparse-tutorial
Additionally there is quite commonly used click
library, which you would need to install via pip
and uses a decorator syntax, that we have not seen yet, so it can remain as self study.
Usually when we send our Python code to someone else, we do not expect them to read the whole code but reading the help should be enough for them to use it and change parameters.
For Python CLI tools, you would get the help this way, which you see is the same as for git
:
python3 hello.py --help
Here's how to create Python command line application with switches:
But first lets start with a function that greets the user for a given number of times and optionally can indent the greeting.
Lets save the following code into hello.py
file.
def hello(count, name, indent=False):
"""Simple program that greets 'name' for a total of 'count' times and optionally indents."""
for _ in range(count):
if indent:
print(" ", end="")
print(f"Hello {name}!")
count = 5
name = "Tyna"
indent = True
hello(count, name, indent)
And run it as usual as python hello.py
.
Now we want the arguments count
, name
and indent
to be enabled as CLI options and come from command line arguments when you start the script.
import argparse
parser = argparse.ArgumentParser(description='argparse greeting')
parser.add_argument('-n', '--name', help='a name to repeat', required=True)
parser.add_argument('-c', '--count', help='how many times', required=True, type=int)
parser.add_argument("--indent", action="store_true", help=("name will be indented by 4 spaces"))
def hello(count, name, indent=False):
"""Simple program that greets 'name' for a total of 'count' times and optionally indents."""
for _ in range(count):
if indent:
print(" ", end="")
print(f"Hello {name}!")
args = parser.parse_args()
hello(args.count, args.name, args.indent)
The first step in using the argparse is creating an ArgumentParser
object with some description.
Then you fill an ArgumentParser
with information about program
arguments, which is done by making calls to the add_argument()
method.
This information is stored and used when parse_args()
is called.
You can set parameters as required by adding required=True
option.
It is also possible to their type
, which will try to convert the variable to the data type announced.
In order to allow simple storing of boolean flags True/False
, you can use the action="store_true"
parameter.
python3 hello.py
python3 hello.py --help
python3 hello.py --name PyLady
python3 hello.py --count 5
python3 hello.py --count 5 --name PyLady
python3 hello.py --count 5 --name PyLady --indent
That is already a very solid first program is it not?
You can of course define arguments, which are positional
in the same way as when you are defining and using function arguments. The parsing will expect all arguments to be in the order, in which you defined them.
To try it, replace the first two lines with name
and count
arguments with following lines:
parser.add_argument("name", help='a name to repeat')
parser.add_argument("count", help='how many times', type=int)
From now on, the order in which you provide name
and count
arguments will be important. The named arguments can still be provided before or after the positional arguments.
python3 hello.py PyLady 5 --indent
An example of a wrong call would be:
python3 hello.py 5 PyLady
Which should run into following error:
hello.py: error: argument count: invalid int value: 'PyLady'
Switch names begin, according to Unix convention, with hyphens: one hyphen -
for one-letter abbreviations, two hyphens --
for multi-letter names.
One switch can have more than one name - short option and long option.
This example shows how it is usually done for example of logging
setup - although it does not apply for our simple example.
parser.add_argument(
"-v", "--verbosity", type=int, default=3, choices=[0, 1, 2, 3, 4],
help=(
"Set verbosity of log output "
"(4=DEBUG, 3=INFO, 2=WARNING, 1=ERROR, 0=CRITICAL). (default: 3)"
),
)
Parameter names with hyphens
inside them will automatically turn them into variable names
with underscores
, as it is not possible to have a hyphen -
in variable name in Python.
parser.add_argument(
"--extreme-universe",
action="store_true", help=("Computations will return all results to the power of 2.")
)
args = parser.parse_args()
print(args.extreme_universe)
If you use more options with two hyphens, you need to access the values from the args
object via the first option, as in this example:
parser.add_argument('-n', '--name', '--firstname', help='a name to repeat', required=True)
hello(args.count, args.name, args.indent)
# both work
python3 hello.py --name PyLady --count 5
python3 hello.py --firstname PyLady --count 5
This has been a short introduction into working with CLI.