- https://amir.rachum.com/blog/2017/07/28/python-entry-points/
- (随心所欲翻译.)
这篇文章将会聊聊 python 代码中的入口点.很多人可能知道, 入口点一般会放在 setup.py 文件中, 经过打包后可以作为命令行使用, 不过很少有人会去用它.接下来, 我将会介绍如何使用入口点生成 python 包, 之后就可以让别人在代码中或者命令行下使用.
安装过 python 包的都知道使用
pip install <somepackages>
, setup.py 就是定义了你自己开发的包的相关信息, 然后可以打包上传到 python 的包管理中心供别人下载. 而入口点 entry_points 可以让包作为命令行工具使用.
Snek,Inc.
恭喜你! 你刚刚被任命为 "snek 半导体和软件公司" 的 CEO, 作为 CEO, 你的第一个工作是让员工开发出 snek 的原型系统, 很快, 工程师就做出来了, 它是一个 python 脚本, snek.py:
ascii_snek = """\
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`"""
def main():
print(ascii_snek)
if __name__ == '__main__':
main()
在公司产品发布的那一天, 你演示了这个原型系统, 运行很顺利:
$ python snek.py
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`
SaaS--Snek as a Service
不幸的是, 用户不会使用 python, 他们只想在电脑的命名行下直接使用 Snek 的服务, 于是工程师们加班加点作出了下一个版本, 让 snek 在安装时自动生成控制台脚本, 这样就可以在命令行下运行了.他们是怎么做的? 只需要在 setup.py 脚本中包含包名, 依赖等信息, 像下面这样:
下面的代码就是指定了应该从 snek 脚本的 main 函数开始执行.
from setuptools import setup
setup(
name='snek',
entry_points={
'console_scripts': [
'snek = snek:main',
],
}
)
工程师说, 控制台脚本就是特殊的入口点, setuptools 在你的包被别人安装时, 读取其中的内容并生成某些脚本文件.现在, 让我们从源代码中安装(当然你可以发布为 python 库, 让别人使用 pip 下载安装):
$ python setup.py develop
running develop
running egg_info
writing snek.egg-info\PKG-INFO
writing dependency_links to snek.egg-info\dependency_links.txt
writing entry points to snek.egg-info\entry_points.txt
writing top-level names to snek.egg-info\top_level.txt
reading manifest file 'snek.egg-info\SOURCES.txt'
writing manifest file 'snek.egg-info\SOURCES.txt'
running build_ext
Creating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)
snek 0.0.0 is already the active version in easy-install.pth
Installing snek-script.py script to C:\Program Files (x86)\Py36-32\Scripts
Installing snek.exe script to C:\Program Files (x86)\Py36-32\Scripts
Installing snek.exe.manifest script to C:\Program Files (x86)\Py36-32\Scripts
Installed c:\users\rachum\notebooks
Processing dependencies for snek==0.0.0
Finished processing dependencies for snek==0.0.0
在公司的年度产品会上, 你展示了这个 amazing 的产品:
$ snek
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`
Snek for Everyone
没有人不喜欢 Snek, 公司的 IPO 超过了 60 亿美元.有些高级用户希望为他们量身定制高级的版本.工程师又加班加点做了出来:
"""Print an ASCII Snek.
Usage:
snek [--type=TYPE]
"""
import docopt
normal_snek = """\
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`"""
fancy_snek = """\
_,..,,,_
'``````^~"-,_`"-,_
.-~c~-. `~:. ^-.
`~~~-.c ; `:. `-, _.-~~^^~:.
`. ; _,--~~~~-._ `:. ~. .~ `.
.` ;' .:` `: `:. ` _.:-,. `.
.'.: :' _.-~^~-. `. `..'.: `.'
: .'_:' .-'`. :. .: .'`. : ;
: `-'.:' `. `^~~^` .:. `. ; ;
`-.__,-~ ~-. ,'':'.__.` :'~--..--' ':. .:'
':..___.:'
"""
def get_sneks():
return {
'normal': normal_snek,
'fancy': fancy_snek,
}
def main():
args = docopt.docopt(__doc__)
snek_type = args['--type'] or 'normal'
print(get_sneks()[snek_type])
if __name__ == '__main__':
main()
他们加了一个豪华版的 Snek, 这让高级用户特别开心.
$ snek
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`
$ snek --type fancy
_,..,,,_
'``````^~"-,_`"-,_
.-~c~-. `~:. ^-.
`~~~-.c ; `:. `-, _.-~~^^~:.
`. ; _,--~~~~-._ `:. ~. .~ `.
.` ;' .:` `: `:. ` _.:-,. `.
.'.: :' _.-~^~-. `. `..'.: `.'
: .'_:' .-'`. :. .: .'`. : ;
: `-'.:' `. `^~~^` .:. `. ; ;
`-.__,-~ ~-. ,'':'.__.` :'~--..--' ':. .:'
':..___.:'
Snek International Community
全球数百万人都在使用 snek, 人们对 snek 不同版本的需求越来越高, 而且一些 snek 的专业用户 (程序员) 要求 snek 可以定制, 他们想开发自己的 snek 版本.
"""Print an ASCII Snek.
Usage:
snek [--type=TYPE]
"""
import docopt
import pkg_resources
normal_snek = """\
--..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`"""
fancy_snek = """\
_,..,,,_
'``````^~"-,_`"-,_
.-~c~-. `~:. ^-.
`~~~-.c ; `:. `-, _.-~~^^~:.
`. ; _,--~~~~-._ `:. ~. .~ `.
.` ;' .:` `: `:. ` _.:-,. `.
.'.: :' _.-~^~-. `. `..'.: `.'
: .'_:' .-'`. :. .: .'`. : ;
: `-'.:' `. `^~~^` .:. `. ; ;
`-.__,-~ ~-. ,'':'.__.` :'~--..--' ':. .:'
':..___.:'
"""
def get_sneks():
sneks = {
'normal': normal_snek,
'fancy': fancy_snek,
}
for entry_point in pkg_resources.iter_entry_points('snek_types'):
sneks[entry_point.name] = entry_point.load()
return sneks
def main():
args = docopt.docopt(__doc__)
snek_type = args['--type'] or 'normal'
print(get_sneks()[snek_type])
if __name__ == '__main__':
main()
他们增加了 snek 的基础架构, 当 snek 运行时, 使用被称作 snek_types 的入口点注册其他类型的 snek, 这样就能动态的在控制台输出不同的 snek 版本.
具体来说, get_sneks 中的
pkg_resources.iter_entry_points('snek_types')
遍历所有注册到入口点的 snek 名, 然后加入 snek 版本中.于是, 开发者们加入了一个可爱版本的 snek, 命名为 cute_snek.py :
cute_snek = r"""
/^\/^\
_|__| O|
\//~ \_/ \
\____|__________/ \
\_______ \
`\ \ \
| | \
// \
// \
// \ \
// \ \
// _----_ \ \
// _-~ ~-_ | |
( ( _-~ _--_ ~-_ _/ |
\ ~-____-~ _-~ ~-_ ~-_-~ /
~-_ _-~ ~-_ _-~
~--______-~ ~-___-~
"""
如何找到这个可爱版本的 snek 呢? 像下面这样定义 setup.py:
代码中指定了从 cute_snek.py 脚本寻找 cute_snek.
- from setuptools import setup
- setup(
- name='cute_snek',
- entry_points={
- 'snek_types': [
- 'cute = cute_snek:cute_snek',
- ],
- }
- )
然后像之前一样打包:
$ cd cute_snek && python setup.py develop
- running develop
- running egg_info
writing cute_snek.egg-info\PKG-INFO
writing dependency_links to cute_snek.egg-info\dependency_links.txt
writing entry points to cute_snek.egg-info\entry_points.txt
writing top-level names to cute_snek.egg-info\top_level.txt
- reading manifest file 'cute_snek.egg-info\SOURCES.txt'
- writing manifest file 'cute_snek.egg-info\SOURCES.txt'
- running build_ext
- Creating c:\program files (x86)\py36-32\lib\site-packages\cute-snek.egg-link (link to .)
cute-snek 0.0.0 is already the active version in easy-install.pth
Installed c:\users\rachum\cute_snek
- Processing dependencies for cute-snek==0.0.0
- Finished processing dependencies for cute-snek==0.0.0
现在我们就能在命令行下成功的运行这个可爱版本的 snek, 这是从 cute_snek 中动态加载的:
- $ snek --type cute
- /^\/^\
- _|__| O|
- \//~ \_/ \
- \____|__________/ \
- \_______ \
- `\ \ \
- | | \
- // \
- // \
- // \ \
- // \ \
- // _----_ \ \
- // _-~ ~-_ | |
- ( ( _-~ _--_ ~-_ _/ |
- \ ~-____-~ _-~ ~-_ ~-_-~ /
- ~-_ _-~ ~-_ _-~
- ~--______-~ ~-___-~
既然 cute_snek 可以动态的加载, 那么所有类型的 snek 应该都可以动态加载, 于是工程师们又修改了代码:
所有的 snek 都从 snek_types 中加载.
- from setuptools import setup
- setup(
- name='cute_snek',
- entry_points={
- 'snek_types': [
- 'cute = cute_snek:cute_snek',
- 'normal = snek:normal_snek',
- 'fancy = snek:fancy_snek',
- ],
- }
- )
- # 同时修改之前文件中的 get_sneks()函数:
- def get_sneks():
- #sneks = {
- # 'normal': normal_snek,
- # 'fancy': fancy_snek,
- #}
- # 将 snek 修改为空字典
- snek = {}
- for entry_point in pkg_resources.iter_entry_points('snek_types'):
- sneks[entry_point.name] = entry_point.load()
- return sneks
现在重新打包 snek:
$ python setup.py develop
- running develop
- running egg_info
- writing snek.egg-info\PKG-INFO
writing dependency_links to snek.egg-info\dependency_links.txt
writing entry points to snek.egg-info\entry_points.txt
- writing top-level names to snek.egg-info\top_level.txt
- reading manifest file 'snek.egg-info\SOURCES.txt'
- writing manifest file 'snek.egg-info\SOURCES.txt'
- running build_ext
- Creating c:\program files (x86)\py36-32\lib\site-packages\snek.egg-link (link to .)
- snek 0.0.0 is already the active version in easy-install.pth
- Installing snek-script.py script to C:\Program Files (x86)\Py36-32\Scripts
- Installing snek.exe script to C:\Program Files (x86)\Py36-32\Scripts
- Installing snek.exe.manifest script to C:\Program Files (x86)\Py36-32\Scripts
Installed c:\users\rachum\notebooks
- Processing dependencies for snek==0.0.0
- Finished processing dependencies for snek==0.0.0
大功告成!!!
- $ snek
- --..,_ _,.--.
`'.'. .'`__ o `;__.'.'. .'.'`'---'` `'.`'--....--'`.'`'--....--'`
- $ snek --type fancy
- _,..,,,_
- '``````^~"-,_`"-,_
.-~c~-. `~:. ^-.
- `~~~-.c ; `:. `-, _.-~~^^~:.
- `. ; _,--~~~~-._ `:. ~. .~ `.
- .` ;' .:` `: `:. ` _.:-,. `.
- .'.: :' _.-~^~-. `. `..'.: `.'
- : .'_:' .-'`. :. .: .'`. : ;
- : `-'.:' `. `^~~^` .:. `. ; ;
- `-.__,-~ ~-. ,'':'.__.` :'~--..--' ':. .:'
- ':..___.:'
- $ snek --type cute
- /^\/^\
- _|__| O|
- \//~ \_/ \
- \____|__________/ \
- \_______ \
- `\ \ \
- | | \
- // \
- // \
- // \ \
- // \ \
- // _----_ \ \
- // _-~ ~-_ | |
- ( ( _-~ _--_ ~-_ _/ |
- \ ~-____-~ _-~ ~-_ ~-_-~ /
- ~-_ _-~ ~-_ _-~
- ~--______-~ ~-___-~
到此为止, 你应该大概知道了如何使用 python 中的入口点了吧.
来源: https://juejin.im/entry/5b1a32d5f265da6e381927ef