Python Fire: How To Create CLIs from ANY Python Object
Tags: python
Published: 2021-04-23 09:34:52

This blog post summarizes the use cases of Python Fire, explained by [David Bieber](https://www.linkedin.com/in/davidjbieber), a Software Engineer at Google Brain in a webinar organized by Women Who Code Python Track.

***

## Hello, Python Fire!
Fire is a Python library that can create a Command-line Interface from absolutely any Python object, created for the purpose of unifying scripting, testing, and operations for complex systems. It’s named “Fire” as it instantly fires off (executes) our command. It can be of great help in the following workflows:

- Creating Command-line interfaces
- Developing and Debugging Python code
- Exploring third-party Python projects
Let’s install fire and look at the generic pattern to use fire on the Python programs/functions that we create.
```python
pip install fire
import fire
fire.Fire(function_name)
```
***
## Creating CLIs
Let’s call fire on our very own “Hello World!” program.

``` python
import fire
def hello(name="world"):
    return "Hello " + name + "!"
if __name__== '__main__':
    fire.Fire(hello)
# Fire now creates a CLI for our program as shown below.

> hello            # Hello world!
> hello @My_Name   # Hello @My_Name!
> hello --name=WWC # Hello WWC!
```
What does calling Fire do?
Fire consumes the arguments and uses them to

- Instantiate a class
- Call a function
- Get a member or property

And, it repeats the process until all the arguments have been exhausted. After completion, the resulting component is serialized in a human-readable way.

To reiterate, we can call fire.Fire with any Python class, object, function, module, dict and so on!

***
## Using Multiple Commands
Let’s see a simple Calculator example, that contains methods add and multiply which each takes two arguments and computes sum and product respectively.
```python
import fire
class Calculator(object):
     def add(self,x,y):
         return x + y
     def multiply(self,x,y):
         return x * y
if __name__== '__main__':
      fire.Fire(Calculator)
```
As expected Fire creates a CLI from which we should be able to run multiple commands including inspecting the class, add and multiply functions.
```
> calculator add 1 2 # 3
> calculator multiply 3 4 # 12
> calculator
Usage: calculator add
       calculator multiply
```

***
## Using Hierarchical Commands
In the following code snippet, we have a Tools class, which when instantiated would in turn instantiate the Calculator and Widget classes.
``` python
import fire
class Tools(object):
     def __init__(self):
         self.calculator = Calculator()
         self.widget = Widget()
if __name__== '__main__':
      fire.Fire(Tools)
# The CLI that Fire generates looks allows us to access the respective classes and class methods 
> tools calculator add 1 2 # 3
> tools calculator multiply 3 4 # 12
> tools 
Usage: tools calculator 
       tools widget 
```

***
## Debugging and Development
Python Fire library is indeed very helpful in debugging and development where we can just go ahead and call `fire.Fire()` on any Python script without any argument and use in the command-line.

There’s also an option to use the ‘`interactive`’ flag which as shown below, imports useful objects and allows us to directly use them from the IPython shell without having to import modules, function calls etc.
``` python
> calc -- --interactive
Fire is starting Python REPL with the following objects:
Modules: fire
Objects: Calculator, calc, component, result, trace
IPython -- An enhanced Interactive Python
[1]: calc.add(1,2)
[2]: calc.multiply(3,4)
```
***
## Exploring Third-Party Python Projects
As with above-explained examples, we might as well call `fire.Fire()` on third party modules whose source code we may not necessarily have access to. In the latest release of fire, we can directly call `python -m fire` from the command-line

Let’s walk through an example with the image processing library PIL. Suppose we have a Python script `imagefire.py` with the following lines and we want to open a `giraffe.png` image and perform some operations on the image.
```python
from PIL import Image
import fire
fire.Fire(Image)
> imagefire.py open giraffe.png - convert L - resize 100,100 - save giraffe_out.png
```
The above code opens the image, converts it to grayscale, resizes it to the specified size, and then saves the resulting image under the name `giraffe_out.png`. The recent release of fire allows us to do the same all the more easily!

``` python
# NEW release of Fire
> python -m fire PIL.Image open giraffe.png - convert L - resize 100,100 - save giraffe_out.png
```
***
## References
If you’re looking to delve deeper into Python Fire, the following are some of the resources
[1] https://google.github.io/python-fire/guide/
[2] https://github.com/google/python-fire

Cover Image: Photo by <a href="https://unsplash.com/@becomingsilence?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Roland Larsson</a> on <a href="https://unsplash.com/s/photos/fire-abstract?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>