CLI Applications
Command Line Interface (CLI) applications are applications that take command line arguments to pass in information to the application so as to avoid interacting with the application to input information. Command line arguments include information such as input and output filenames, switches to say yes or no. Following examples may be familiar to you:
copy file1.csv file2.csvcopyis the CLI application. This application takes only command line arguments and does not have commands.file1.csvis the first argument and is assumed to be the source file that is to be copiedfile2.csvis the second command line argument and is assumed to be the name of the copy of the source file.
git clone https://github.com/satish-annigeri/rcdesign.gitgitis the CLI application. This application has several commands which can be displayed with thegit --helpcommand.cloneis the commandhttps://github.com/satish-annigeri/rcdesign.gitis the argument to the command and is assumed to be the repository to be cloned
Catching Command Line Arguments with sys.argv
When an application is called from the command line (Command Prompt in Windows orterminal in GNU/Linux and macOS), the operating system shell passes on information about the command and the command line arguments to the application. Within the program, the programming language can access these command line arguments and interpret and act on them based on its own logic.
The built-in module sys can access the command line arguments:
import sys
print(type(sys.argv), len(sys.argv))
for i, arg in enumerate(sys.argv):
print(i, arg)
Alert
accessing command line arguments requires that the application be called from the command line. This will not work inside the Python REPL.
Run this application from the command line in the following ways and see the output"
You should see the following output:
> uv run -- python cli_app.py
<class 'list'> 1
0 cli_app.py
> uv run -- python cli_app.py command
<class 'list'> 2
0 cli_app.py
1 command
> uv run -- python cli_app.py command argument
<class 'list'> 3
0 cli_app.py
1 command
2 argument
sys.argvis alist- The first element at index 0 of
sys.argvis the name of the application itself,cli_app.pyin our case - The other elements depend on the additional arguments typed on the command line
- The command line arguments are passed on to the application as they are typed and it is up to the application to make use of them as required
Python has modules specifically to assist in parsing command line arguments and argparse is the one of the earliest. However, we will use a module named typer which is simple to use and fairly capable.
Typer
Typer is a library for building CLI applications and is based on Python type hints. It relies on the parameters of a specified function (usually named main() but could be anything else) and their type hints and generates the CLI interface with little to no additional coding on the part of the programmer. Let us begin with a simple example with only arguments (that is, no multiple commands).
| cli_app.py | |
|---|---|
> uv run cli_app.py
Usage: cli_app.py [OPTIONS] DIR PATTERN
Try 'cli_app.py --help' for help.
╭─ Error ──────────────────────────────────────────────────────────────────────╮
│ Missing argument 'DIR'. │
╰──────────────────────────────────────────────────────────────────────────────╯
> uv run -- python cli_app.py --help
Usage: cli_app.py [OPTIONS] DIR PATTERN
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * dir TEXT [required] │
│ * pattern TEXT [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --recurse --no-recurse [default: no-recurse] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
Usage help tells us the following:
- Arguments
dirandpatternare required, and both are of type text - Argument
--recurseis optional and the default value isno-recurse - Arguement
--helpdisplays the help page
Let us try with one argument, namely ., the current directory:
> uv run -- python cli_app.py .
Usage: cli_app.py [OPTIONS] DIR PATTERN
Try 'cli_app.py --help' for help.
╭─ Error ──────────────────────────────────────────────────────────────────────╮
│ Missing argument 'PATTERN'. │
╰──────────────────────────────────────────────────────────────────────────────╯
Let us try with two arguments, . fir the directory and *.py for pattern:
Note
It may be necessary to enclose "*.py" within double quotes to prevent the command shell from interpreting it wrongly.
Let us test one last time:
> uv run -- python cli_app.py , "*.py" --recurse
dir='.'
pattern='*.py'
recurse=True
> uv run -- python cli_app.py , "*.py" --no-recurse
dir='.'
pattern='*.py'
recurse=False
To build CLI applications with multiple commands and a separate set of arguments for each command, study the Typer documentation.
Typer has been used in the Session 10 searchdir.py example and in Snippet 3 CLI application.
An alternative to Typer is the package Click. In fact, Typer depends on Click. While requiring a slightly steeper learning curve, Click is versatle and capable compared to Typer.
Example with only command line arguments and no commands
Let us build a dummy main() functions as examples.
A Python script secprop_cli.py takes the name of a input file as the first argument and an optional second argument representing the name of an output file.
> uv run -- python secprop_cli.app --help
Usage: secprop_cli.py [OPTIONS] INPUT
╭─ Arguments ──────────────────────────────────────────────────────────────────╮
│ * input TEXT [required] │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --output TEXT │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
> uv run -- python secprop_cli.py sections.csv
input='sections.csv', output=None
> uv run -- python sections,csv --output sections_geomprop.csv
uv run -- python secprop_cli.py sections.csv --output sections_prop.csv
input='sections.csv', output='sections_prop.csv'
Example with commands
This example is copied from Typer documentation, with one change (Ms. from goodbye() is deleted).
| greet.py | |
|---|---|
Note
- The name of the application is
greet.py - Th
greet.pyCLI application has two subcommands,helloandgoodbye - Command
hellotakes one argument:- Required argument
name
- Required argument
- Command
goodbyetakes two arguments:- Required argument
name - Optional boolean argument
formal, which defaults toFalseif not given.
- Required argument
Let us try out this CLI application:
> uv run -- python greet.py --help
Usage: greet.py [OPTIONS] COMMAND [ARGS]...
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy │
│ it or customize the installation. │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ hello │
│ goodbye │
╰──────────────────────────────────────────────────────────────────────────────╯
> uv run -- python greet.py hello Raj
Hello Raj
> uv run -- python greet.py goodbye Raj
Bye Raj!
> uv run -- python greet.py goodbye Raj --formal
Goodbye Raj. Have a good day.