Generating Command-Line Interfaces (CLI) with Fire in Python
A Command-line interface (CLI) is a way to interact with computers using textual commands.
A lot of tools that don't require GUIs are written as CLI tools/utilities. Although Python has the built-in
argparse module, other libraries with similar functionality do exist.
These libraries can help us in writing CLI scripts, providing services like parsing options and flags to much more advanced CLI functionality.
This article discusses the Python Fire library, written by Google Inc., a useful tool to create CLI with minimal code.
General Form of CLI Applications
Before we start with the
Fire library let's try to understand the basics of command-line interface programs in general. Depending on the program and command, the general pattern of a CLI can be summed up as follows:
prompt command parameter1 parameter2 ... parameterN
- prompt is a sequence of characters that prompts the user to input a command
- command is the name of the program that the user is executing (e.g.
- parameters are optional tokens that augment or modify the command output
A CLI program is executed by typing the name of the program after the
prompt appears, in this case the $ symbol.
Here we are using the
ls command that returns a list of file names in a directory, the current directory being the default:
$ ls README.md python
You can modify the behavior or output of a command-line program by providing it with a list of tokens or parameters better known as flags. Let's try out a flag of the
$ ls -l -rwxrwxrwx 1 pandeytapan pandeytapan 10 Sep 23 18:29 README.md drwxrwxrwx 1 pandeytapan pandeytapan 512 Sep 23 18:29 python
As you can see, after passing the
-l flag, we get additional information for each entry like the owner, group, and file size.
Flags which have a single hyphen (
-) are called short options, while those with two hyphens (
--) are called long options. Both kinds can be used together in a single command, like in the following example:
$ ls -l --time-style=full-iso -rwxrwxrwx 1 pandeytapan pandeytapan 10 2020-09-23 18:29:25.501149000 +0530 README.md drwxrwxrwx 1 pandeytapan pandeytapan 512 2020-09-23 18:29:25.506148600 +0530 python
The difference between short and long options:
- Short options can be chained together
- If we want to use both the
-ashort options we just type
- Short options are denoted by a single character while long options have a full hyphen-separated name and cannot be chained together.
--time-style flag works with the
-l flag and controls the display time format for a directory listing.
A CLI provides an easy way for the user to configure and run an application from the command line. Google's Python Fire library makes it easy to add a CLI processing component to any existing Python script.
Let's see how to make a command line application using Python Fire.
Let's go ahead and install the library using
$ pip install fire
Python Fire works on any Python object i.e. functions, classes, dictionaries, lists etc. Let's try to understand the usage of the
Python Fire library through some examples.
Generating CLI Application with Python Fire
Let's make a script, say,
fire_cli.py and put a function within it:
def greet_mankind(): """Greets you with Hello World""" return 'Hello World'
On running this program on Python shell the output is:
>>> from fire_cli import greet_mankind >>> greet_mankind() 'Hello World' >>>
We can easily turn this script into a CLI application using Python Fire:
import fire def greet_mankind(): """ Returns a textual message """ return 'Hello World' if __name__ == '__main__': fire.Fire()
fire.Fire() calls turns the module i.e.
fire_cli.py into a Fire CLI application. Moreover it has exposed the
greet_mankind() function as command, automatically.
Now we can save and run the above script as CLI as follows:
$ python fire_greet_mk_cli.py greet_mankind Hello World
As a refresher, let's break down the call:
- $ is the prompt
- python is the command interpreter
- fire_cli.py is the module that contains the CLI command
- greet_mankind is the command
Passing Arguments to a Command
Let us make another CLI application that takes a name as a parameter and displays a custom greeting message:
import fire def greetings(name): ''' Returns a greeting message Parameters ---------- name : string String that represents the addresses name Returns ------- string greeting message concatenated with name ''' return 'Hello %s' % name if __name__ == '__main__': fire.Fire()
Here, we've now got a function that accepts a string -
name. Python Fire automatically picks this up and if we supply an argument after the
greetings call, it'll bind that input to the
name parameter. We've also added a comment as a sort of documentation for the
Here's how we can run this command from the command line:
$ python fire_greet_cli.py greetings Robin Hello Robin
A Fire CLI application can use
--help flags to check the command description generated from Python docs:
python fire_greet_cli.py greetings --help NAME fire_greet_cli.py greetings - Returns a greeting message SYNOPSIS fire_greet_cli.py greetings NAME DESCRIPTION Returns a greetings message POSITIONAL ARGUMENTS NAME String that represents the addresses name NOTES You can also use flags syntax for POSITIONAL ARGUMENTS
Setting a Function as Entry Point
With slight modification we can control the exposure of the
greetings() function to the command-line and set it as the default entry-point:
import fire def greetings(name): ''' Returns a greeting message :param name: string argument :return: greeting message appended with name ''' return 'Hello %s' % name if __name__ == '__main__': fire.Fire(greetings)
This is how we will run the command now:
$ python fire_greet_cli.py Robin Hello Robin
So this time we no longer need to call the command as we have defined
greetings implicitly as an entry point using
Fire(). One thing to be noted here is that with this version, we can only pass a single argument :
$ python fire_greet_cli.py Robin Hood ERROR: Could not consume arg: Hood ... $ python fire_greet_cli.py Robin Hello Robin
The Fire library also works with classes. Let's define a class
CustomSequence that generates and returns a list of numbers between
import fire class CustomSequence: '''Class that generates a sequence of numbers''' def __init__(self, offset=1): ''' Parameters ---------- offset : int, optional Number controlling the difference between two generated values ''' self.offset = offset def generate(self, start, stop): ''' Generates the sequence of numbers Parameters ---------- start : int Number that represents the elements lower bound stop : int Number that represents the elements upper bound Returns ------- string a string that represents the generated sequence ''' return ' '.join(str(item) for item in range(start, stop, self.offset)) if __name__ == '__main__': fire.Fire(CustomSequence)
This is how we generate a sequence using this command-line utility:
$ python fire_gen_cli.py generate 1 10 1 2 3 4 5 6 7 8 9
We used a class instead of a function because unlike functions if we want to pass an argument to the constructor, it always has to be represented as a command line flag with double hyphens (e.g.
Therefore, our CLI application supports an optional argument
--offset that will be passed on to the class constructor. This modifies the output by controlling the difference between two consecutive generated values:
Here's the output with offset value of 2:
$ python fire_gen_cli.py generate 1 10 --offset=2 1 3 5 7 9
The constructor's arguments are always passed using the flag syntax whereas arguments to other methods or functions are passed positionally or by name :
$ python fire_gen_cli.py generate --start=10 --stop=20 10 11 12 13 14 15 16 17 18 19 $ python fire_gen_cli.py generate 10 20 10 11 12 13 14 15 16 17 18 19 $ python fire_gen_cli.py generate --start=10 --stop=20 --offset=2 10 12 14 16 18
We can check the usage of the
generate command using the
--help flag. This will give the usage information for the CLI :
$ python fire_gen_cli.py generate --help INFO: Showing help with the command 'fire_gen_cli.py generate -- --help'. NAME fire_gen_cli.py generate - Generates the sequence of numbers SYNOPSIS fire_gen_cli.py generate START STOP DESCRIPTION Generates the sequence of numbers POSITIONAL ARGUMENTS START Number that represents the first value for the sequence STOP Number that represents the ending value for the sequence NOTES You can also use flags syntax for POSITIONAL ARGUMENTS
--help with the module gives us its usage information:
$ python fire_gen_cli.py --help INFO: Showing help with the command 'fire_gen_cli.py -- --help'. NAME fire_gen_cli.py - Class that generates a sequence of numbers SYNOPSIS fire_gen_cli.py <flags> DESCRIPTION Class that generates a sequence of numbers FLAGS --offset=OFFSET
Fire CLIs comes with many built-in flags. We have already seen
--help, though, another useful flag is
--interactive. Using this flag puts us in Python REPL mode, with the module already defined.
This is quite useful for testing commands:
$ python fire_greet_cli.py -- --interactive Fire is starting a Python REPL with the following objects: Modules: fire Objects: component, fire_greet_cli.py, greetings, result, trace Python 3.7.8 (tags/v3.7.8:4b47a5b6ba, Jun 28 2020, 08:53:46) [MSC v.1916 64 bit (AMD64)] Type 'copyright', 'credits' or 'license' for more information IPython 7.16.1 -- An enhanced Interactive Python. Type '?' for help. In : greetings("Robin") Out: 'Hello Robin'
Note that Fire flags should be separated from other options with two hyphens (
--), so if we want to use both
--interactiveflags in a command, it would look something like this:
$ python fire_greet_cli.py -- --help --interactive
Google's Python Fire library is a quick and easy way to generate command line interfaces (CLIs) for nearly any Python object. In this article, we've gone over how to install Python Fire, as well as generate simple command-line interfaces.Reference: stackabuse.com