fire - Python CLI Tool#
Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.
Overview#
Fire 是一个由 Google 的团队维护, 但是并不作为 Google 的产品的 Python 开源项目. 该项目 2014 年就发布了. 和大部分命令行框架不同的是, fire 可以将 Python 中的函数, 方法, 类直接转化为一个命令行工具, 而无需重新编写 Wrapper. 该项目是我见过的 Python 社区中的命令行工具中最简单, 最易用的一个. 虽然它不适合作为非常复杂的 CLI 工具的底层框架, 但是它几乎适用于 90% 的情况. 并且它没有任何外部依赖, 安装交付非常方便.
How it Work#
任何 callable 的对象如果被 fire.Fire(callable_object)
包装, 那么这个对象就可以被当做命令行工具使用. 这个对象可以是函数, 类, 方法.
callable 对象的参数就是命令行参数.
- callable 对象中的任何 mandatory 的参数会变成 CLI 的 mandatory 参数.
你可以按照定义的顺序传入参数, 也可以下面四种方式中的任何一种传入参数
--arg_name value
,--arg_name=value
,--arg-name value
,--arg-name=value
. arg name 既可以用 underscore 也可以用 hyphen, 即时 Python 中的变量只能用 underscore. 你既可以用空格也可以用等号来分隔参数名和参数值.
callable 对象中的任何 optional 的参数会变成 CLI 的 optional 参数. 如果你不指定, 那么 callable 对象中的默认参数值将会被使用.
如果你只指定了
--arg_name
但没有指定 value, 那么这个值将会被视为 True. 你可以在参数名前加 no 来传递一个 False, 例如--noarg_name
.传递某个 arg name 的时候不仅可以用
--arg_name
, 还可以用首字母简写-a
(其中 a 这里只是个例子, 实际取决于你的参数名)如果你 fire 的对象是一个类, 那么类的方法将会被视为 sub command.
如果你 fire 的对象是一个类, 并且它的属性里是一些其他类的实例, 那么其他类将会被视为 sub command, 而其他类的方法将会被视为 sub command 的 sub command.
- fire 会自动根据参数和 doc string 生成 CLI 文档.
根据参数是否可选以及它们的默认值会自动生成参数文档.
doc string 的第一行会被用作 command 的 name, 而剩下的部分则会被用作 command 的 description.
Examples#
Basic Usage#
1# -*- coding: utf-8 -*-
2
3import typing as T
4import fire
5
6
7def main(
8 name,
9 is_kid: T.Optional[bool] = False,
10 age: T.Optional[int] = 18,
11):
12 """
13 this is main function
14
15 this is description
16
17 - sentence 1
18 - sentence 2
19 - sentence 3
20 """
21 print(f"name = {name}")
22 print(f"is_kid = {is_kid}")
23 print(f"age = {age}")
24
25
26if __name__ == "__main__":
27 fire.Fire(main)
$ python basic_usage.py -h
NAME
basic_usage.py - this is main function
SYNOPSIS
basic_usage.py NAME <flags>
DESCRIPTION
this is description
- sentence 1
- sentence 2
- sentence 3
POSITIONAL ARGUMENTS
NAME
FLAGS
-i, --is_kid=IS_KID
Type: typing.Union[bool, NoneType]
Default: False
-a, --age=AGE
Type: typing.Union[int, NoneType]
Default: 18
NOTES
You can also use flags syntax for POSITIONAL ARGUMENTS
$ python basic_usage.py --name alice
name = alice
is_kid = False
age = 18
$ python basic_usage.py --name alice --is_kid
name = alice
is_kid = True
age = 18
$ python basic_usage.py --name alice --age 30
name = alice
is_kid = False
age = 30
Subcommand example 1#
1# -*- coding: utf-8 -*-
2
3"""
4Simple sub command example.
5
6- Class = top level command
7- Method = sub command
8"""
9
10import typing as T
11import fire
12
13
14class App:
15 """
16 Top level command document.
17 """
18 def __call__(self, version: T.Optional[bool] = False):
19 if version:
20 print("0.0.1")
21 else:
22 print("app")
23
24 def config(self):
25 """
26 "config" subcommand document
27 """
28 print("app config")
29
30 def run(self):
31 """
32 "run" subcommand document
33 """
34 print("app run")
35
36
37if __name__ == "__main__":
38 fire.Fire(App())
$ python subcommand_example1.py -h
NAME
subcommand_example1.py - Top level command document.
SYNOPSIS
subcommand_example1.py COMMAND | <flags>
DESCRIPTION
Top level command document.
FLAGS
-v, --version=VERSION
Type: typing.Union[bool, NoneType]
Default: False
COMMANDS
COMMAND is one of the following:
config
"config" subcommand document
run
"run" subcommand document
$ python subcommand_example1.py -v
0.0.1
$ python subcommand_example1.py config
app config
Subcommand example 2#
1# -*- coding: utf-8 -*-
2
3"""
4Advanced sub command example.
5
6- Class = top level command
7- Attribute, it is an instance of another class = sub command
8- Method in other classes = sub command of sub command
9"""
10
11import typing as T
12import fire
13
14
15class S3:
16 """
17 AWS S3 sub command
18 """
19
20 def ls(self):
21 """
22 List s3 buckets
23 """
24 print("run: aws s3 ls")
25
26
27class EC2:
28 """
29 AWS EC2 sub command
30 """
31
32 def list_instances(self):
33 """
34 List ec2 instances
35 """
36 print("run: aws ec2 list-instances")
37
38 def list_vpcs(self):
39 """
40 List ec2 vpc
41 """
42 print("run: aws ec2 list-vpcs")
43
44
45class AWS:
46 """
47 AWS CLI class doc string
48 """
49
50 def __init__(self):
51 self.s3 = S3()
52 self.ec2 = EC2()
53
54 def __call__(self, version: T.Optional[bool] = False):
55 """
56 AWS CLI
57 """
58 if version:
59 print("0.0.1")
60 else:
61 print("run: aws")
62
63
64if __name__ == "__main__":
65 fire.Fire(AWS())
$ python subcommand_example2.py -h
NAME
subcommand_example2.py - AWS CLI class doc string
SYNOPSIS
subcommand_example2.py GROUP | <flags>
DESCRIPTION
AWS CLI class doc string
FLAGS
-v, --version=VERSION
Type: typing.Union[bool, NoneType]
Default: False
GROUPS
GROUP is one of the following:
ec2
AWS EC2 sub command
s3
AWS S3 sub command
$ python subcommand_example2.py -v
0.0.1
$ python subcommand_example2.py s3
NAME
subcommand_example2.py s3 - AWS S3 sub command
SYNOPSIS
subcommand_example2.py s3 COMMAND
DESCRIPTION
AWS S3 sub command
COMMANDS
COMMAND is one of the following:
ls
List s3 buckets
$ python subcommand_example2.py s3 ls
run: aws s3 ls