Prodesire
The sample code and history articles involved have been synchronized to the HelloGithub-Team repository
One, foreword
In our last article, we covered fire’s subcommands, nested commands, and property access, and today we’ll dig deeper into the rest of fire’s features.
This series of articles uses Python 3 as the interpreter by default. If you are still using Python 2, be aware of the differences in syntax and library usageCopy the code
Second, the function of
2.1 Minimal Command implementation
In the previous section, we introduced how you can implement a command-line program by defining a single function. Such as:
import fire
def english(a):
return 'Hello, fire! '
def chinese(a):
return 'Hello, Fire! '
if __name__ == '__main__':
fire.Fire()
Copy the code
But that’s not the easiest way to do it. Fire even lets you implement the command line by defining variables! The above example can be written as follows:
import fire
english = 'Hello, fire! '
chinese = 'Hello, Fire! '
if __name__ == '__main__':
fire.Fire()
Copy the code
2.2 Chain call
In the Fire CLI, you can continuously process the last result through chain calls.
This can be done simply by returning self in the instance method.
In the example below, we implement a simple four-order arithmetic command that chain-calls add, sub, mul, and div.
import fire
class Calculator:
def __init__(self):
self.result = 0
self.express = '0'
def __str__(self):
return f'{self.express} = {self.result}'
def add(self, x):
self.result += x
self.express = f'{self.express}+{x}'
return self
def sub(self, x):
self.result -= x
self.express = f'{self.express}-{x}'
return self
def mul(self, x):
self.result *= x
self.express = f'({self.express}) *{x}'
return self
def div(self, x):
self.result /= x
self.express = f'({self.express}) /{x}'
return self
if __name__ == '__main__':
fire.Fire(Calculator)
Copy the code
Add, sub, mul and div in the above code correspond to the logic of addition, subtraction, multiplication and division, respectively. Each method takes an x parameter as the number involved in the operation and returns self, which allows infinite chain calls. After the chain call ends on the command line, the __str__ method is finally called to print out the result.
__str__ is used in fire for custom serialization. If this method is not provided, the help content will be printed after the chain call completes.
For example, we could call:
$python calculator.py add 1 sub 2 mul 3 div 4 ((+1-2)*3)/4 = -0.75 $python calculator.py add 1 sub 2 mul 3 div 4 add 4 3 the mul 2 sub div 1 (((* 3) (0 + 1-2) / 4 + 4-3) * 2) / 1 = 0.5Copy the code
2.3 Position Parameters and Option Parameters
We’ve also made it clear that you don’t have to explicitly define positional or option parameters in fire.
Using the following example, we will refine the use of two types of parameters:
import fire
class Building(object):
def __init__(self, name, stories=1):
self.name = name
self.stories = stories
def __str__(self):
return f'name: {self.name}, stories: {self.stories}'
def climb_stairs(self, stairs_per_story=10):
yield self.name
for story in range(self.stories):
for stair in range(1, stairs_per_story):
yield stair
yield 'Phew! '
yield 'Done! '
if __name__ == '__main__':
fire.Fire(Building)
Copy the code
- The parameters defined in the constructor (such as
name
和stories
) on the command line only as option arguments (e.g--name
和--stories
). We can call it like this:
$ python example.py --name="Sherrerd Hall" --stories=3
Copy the code
- The parameters defined in the constructor can be placed anywhere in the command. For example, the following two calls are ok:
$ python example.py --name="Sherrerd Hall" climb-stairs --stairs-per-story 10
$ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"
Copy the code
- Default parameters defined in constructors and normal methods (e.g
stories
) is optional on the command line. We can call it like this:
$ python example.py --name="Sherrerd Hall"
Copy the code
- Parameters defined in normal methods such as
stairs_per_story
) can be either positional or option arguments on the command line. We can call it like this:
# as a positional argument
$ python example.py --name="Sherrerd Hall" climb_stairs 10
# as an option parameter
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs_per_story=10
Copy the code
- The bar (
-
) and underline (_
) is equivalent. So it can also be called like this:
# as an option parameter
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs-per-story=10
Copy the code
In addition, fire supports defining *args and **kwargs in functions.
import fire
def fargs(*args):
return str(args)
def fkwargs(**kwargs):
return str(kwargs)
if __name__ == '__main__':
fire.Fire()
Copy the code
- In the function
*args
Is a positional argument on the command line. We can call it like this:
$ python example.py fargs a b c
Copy the code
- In the function
**kwargs
On the command line as an option parameter. We can call it like this:
$ python example.py fargs --a a1 --b b1 --c c1
Copy the code
- By separator
-
You can explicitly tell that the delimiter is followed by a subcommand, not a command parameter. Take a look at the following example:
# No separator is used, upper is used as positional argument
$ python example.py fargs a b c upper
('a'.'b'.'c'.'upper')
# uses the delimiter, upper is used as a subcommand
$ python example.py fargs a b c - upper
('A'.'B'.'C')
Copy the code
- through
fire
The built-in--separator
You can customize the delimiter. This option parameter needs to be followed by a separate--
The back:
$ python example.py a b c X upper -- --separator=X
('A'.'B'.'C')
Copy the code
2.4 Parameter Types
In fire, the type of a parameter is determined by its value. With the following simple code, we can see what type fire resolves when given different values:
import fire
fire.Fire(lambda obj: type(obj).__name__)
Copy the code
$python example.py 10 int $python example.py 10.0float
$ python example.py hello
str
$ python example.py '(1, 2)Py [1,2] list $python example.py True bool $python example.py {name: David} dictCopy the code
If you want to pass numbers as strings, you need to be careful with quotes, either by raising them or by escaping them:
# the number 10
$ python example.py 10
int
# does not handle quotation marks and is still the number 10
$ python example.py "10"
int
# put quotes around it, so it's string "10"
$ python example.py '" 10 "'
str
# another way to cause quotes
$ python example.py "' 10 '"
str
# Escape quotes
$ python example.py \"10\"
str
Copy the code
Consider a more complex scenario where you pass a dictionary with strings in it, so be careful with quotes:
# Recommended Practices
$ python example.py '{"name": "David Bieber"}'
dict
# is also ok
$ python example.py {"name":'"David Bieber"'}
dict
# error, will be resolved to a string
$ python example.py {"name":"David Bieber"}
str
# error, not reported as a single argument (because there is a space in the middle)
$ python example.py {"name": "David Bieber"}
<error>
Copy the code
If True or False is considered Boolean, fire also supports setting name to True via –name or False via –noname:
$ python example.py --obj=True
bool
$ python example.py --obj=False
bool
$ python example.py --obj
bool
$ python example.py --noobj
bool
Copy the code
2.5 Fire built-in option parameters
Fire has some built-in options to make it easier to use command-line programs. To use the built-in options function, add the option argument after –. In the previous section, we introduced the –separator argument. In addition to this, fire supports the following options:
command -- --help
List detailed help informationcommand -- --interactive
Enter interactive modecommand -- --completion [shell]
Generate automatic completion scripts for CLI programs to support automatic completioncommand -- --trace
Get the command’s Fire trace to see what happens after Fire is calledcommand -- --verbose
Gets details including private members
Third, summary
Fire makes command-line programs particularly easy to implement, and this article focuses on chained calls, option arguments, positional arguments, parameter types, and built-in option arguments. Fire doesn’t have many concepts. It’s a true practice of “keep the simple for others and the complex for yourself.”
So much for fire, which is definitely a great tool for writing command line programs. In the next article, we’ll still put fire into action by implementing a simple Git program.
“Explain Open Source Project series” — let the people who are interested in open source projects not be afraid, let the initiator of open source projects not be alone. Follow along as you discover the joys of programming, use, and how easy it is to get involved in open source projects. Welcome to leave a message to contact us, join us, let more people fall in love with open source, contribute to open source ~