Sometimes we have a need:

We define a Python method that takes arguments but wants to expose them on the command line when called.

For example, here is a crawl method:

import requests

def scrape(url, timeout=10) :
    response = requests.get(url, timeout=timeout)
    print(response.text)
Copy the code

Here a scrape method is defined where the first parameter receives the URL, which is the url to crawl, and the second parameter receives timeout, which specifies the timeout time.

We might call it like this:

scrape('https:///www.baidu.com'.10)
Copy the code

If we want to change the parameter to change the URL, we have to change the code.

Sometimes we want to expose these parameters on the command line. In this case, we might use argparse and other libraries to declare what each parameter does one by one. This is very tedious.

parser = argparse.ArgumentParser(description='Scrape Function')
parser.add_argument('url'.type=str.help='an integer for the accumulator')
parser.add_argument('timeout'.type=int.help='sum the integers (default: find the max)')

if __name__ == '__main__':
    args = parser.parse_args()
    scrape(args.url, args.timeout)
Copy the code

So we can call the script smoothly from the command line:

python3 main.py https://www.baidu.com 10
Copy the code

Does it feel like a hassle? Argparse is smelly and long to write, and it’s hard to think about.

Fire

But let’s introduce a library that can do this with just two lines of code.

This library, called Fire, can quickly add command-line argument support to a Python method or class.

First look at the installation method, using PIP3 installation can be:

pip3 install fire
Copy the code

So we’re set up.

use

Let’s look at some examples.

Method supports

The first code example is as follows:

import fire

def hello(name="World") :
  return "Hello %s!" % name

if __name__ == '__main__':
  fire.Fire(hello)
Copy the code

Here we define a hello method, take a name argument, World by default, and output the string Hello plus name.

And then we import the fire library, call its fire method and pass in the hello method declaration, what happens?

Let’s save this code as demo1.py and run it using Python3:

python3 demo1.py
Copy the code

The running results are as follows:

Hello World!
Copy the code

It doesn’t seem that different.

But if we run the following command, we can see something amazing:

python3 demo1.py --help

Copy the code

The running results are as follows:

NAME
    demo1.py

SYNOPSIS
    demo1.py <flags>

FLAGS
    --name=NAME
        Default: 'World'
Copy the code

As you can see, it turns the name argument into an optional argument on the command line, and we can replace the name argument with — name.

Let’s try it:

python3 demo1.py --name 123
Copy the code

Here we pass in a name parameter of 123, and we see that the result is as follows:

Hello 123!
Copy the code

Is it very convenient? We can easily support and replace command-line arguments without argparse.

What if we unset the name parameter by default? The code rewrite is as follows:

import fire

def hello(name) :
  return "Hello %s!" % name

if __name__ == '__main__':
  fire.Fire(hello)
Copy the code

Rerun at this point:

python3 demo1.py --help
Copy the code

The result should look like this:

NAME
    demo1.py

SYNOPSIS
    demo1.py NAME

POSITIONAL ARGUMENTS
    NAME

NOTES
    You can also use flags syntax for POSITIONAL ARGUMENTS
Copy the code

The name parameter becomes mandatory. We must specify this parameter on the command line, and the call will look like this:

python3 demo1.py 123
Copy the code

The result is the same.

Class supports

Of course, the fire library does not only support adding command line support to methods, but also to classes.

Here’s another example:

import fire

class Calculator(object) :    
    def double(self, number) :
        return 2 * number

if __name__ == '__main__':
    fire.Fire(Calculator)

Copy the code

Let’s save this code as demo2.py and run:

python3 demo2.py
Copy the code

The running results are as follows:

NAME
    demo2.py

SYNOPSIS
    demo2.py COMMAND

COMMANDS
    COMMAND is one of the following:

     double
Copy the code

As you can see, here it identifies the methods in the Calculator class, and one of the commands is double, so let’s try calling:

python3 demo2.py double
Copy the code

The running results are as follows:

ERROR: The function received no value for the required argument: number
Usage: demo2.py double NUMBER

For detailed information on this command, run:
  demo2.py double --help
Copy the code

Here we say that we must specify another parameter, called NUMBER, which is also required, so let’s try adding:

python3 demo2.py double 4
Copy the code

The running results are as follows:

8
Copy the code

At this point the correct result can be achieved.

So, taken together, fire can be a class command line, with each command corresponding to a method name and additional optional or required arguments added to the end of the command line arguments.

rewrite

Finally, let’s go back and add command-line argument support to the scrape method we defined in the beginning:

import requests
import fire

def scrape(url, timeout=10) :
    response = requests.get(url, timeout=timeout)
    print(response.text)
    
    
if __name__ == '__main__':
    fire.Fire(scrape)
Copy the code

That’s it! Isn’t it convenient to omit the verbose argparse code?

The call looks like this:

NAME
    main.py

SYNOPSIS
    main.py URL <flags>

POSITIONAL ARGUMENTS
    URL

FLAGS
    --timeout=TIMEOUT
        Default: 10
Copy the code

URL is mandatory and timeout is optional.

Finally call:

python3 main.py https://www.baidu.com 
Copy the code

This makes it easy to pass the URL through the command line.

Of course, timeout is optional. We can specify the timeout argument with — timeout:

python3 main.py https://www.baidu.com --timeout 5
Copy the code

Then both parameters can be successfully assigned, the final effect is to climb baidu, 5 seconds timeout.

How’s that? Is it convenient? Use it, everyone!

For more exciting content, please pay attention to my public account “Attack Coder” and “Cui Qingcai | Jingmi”.