I've really gotten to like the fire command line project from google. It makes it a lot easier to turn your helper files for your jupyter notebook into command line apps which in turns makes it easy to get everything into production. In this document I will show a small extra trick so that you can make fire based command line apps available from the terminal everywhere.

Starting Fire

Let's start by making a command line app called clapp.py.

import os 
import fire 

def hello(person="world"):
    """
    Merely prints hello to a person. Usually the world.
    :param person: Name of someone.
    """
    print(f"hello {person}")


def getcwd():
    """
    Merely prints hello to a person. Usually the world.
    """
    print(os.getcwd())

if __name__ == "__main__":
    fire.Fire({
        'getwd': getwd,
        'hello': hello
    })

The magic of fire is that you can now run these seperate python functions from the terminal. Feel free to type along:

By running this, you can immediately see some nice features from fire:

  • python functions can easily be called from the command line
  • it automatically parses command line arguments into function input
  • docstrings are captured and are part of the help message
  • because the code is now running from the command line, it is every easy to schedule the code with something like cron or airflow
  • this should make it very easy to customize and build your own tools

There are downsides currently though:

  • the command line tool is only available from the folder where you have the file
  • you need to run python ... before the command line app
  • the command line app might have prerequisites which we need to have installed and currenlty the command line app doesn't have a method to check if these prerequisites are met

Fire Everywhere

I will now make a very minor change to the python file.

import os 
import fire 


def hello(person="world"):
    """
    Merely prints hello to a person. Usually the world.
    :param person: Name of someone.
    """
    print(f"hello {person}")


def getcwd():
    """
    Merely prints hello to a person. Usually the world.
    """
    print(os.getcwd())


def main():
    fire.Fire({
        'getcwd': getcwd,
        'hello': hello
    })

Next I will create a setup.py file.

from setuptools import setup

setup(
    name='clapp',
    entry_points={
        'console_scripts': [
            'clapp = clapp:main',
        ],
    }
)

With this change I've made the script installable into pip. The console_scripts part of the setup.py file will point to the main function in the clapp file and let it be an entry point. The nice thing about a setup.py file is that you could also specify prerequisites here (like machine learning libraries or etl requirements).

If you put these two files in the same folder then you can run python setup.py develop to enable the python command to be available globally (assuming you are staying in the same python environment). In fact, we pip is able to confirm that we're installing a tool. Feel free to type along:

Conclusion

Making your own tools is amazing and I've found that automating things in the command line is a great habbit. The nice thing about fire is that it is barely any extra effort to build tools for the command line if you've already built them for the jupyter notebook. There's many features of the tool that I've not discussed (like code completion) but you can find any extra details here.