Cer*_*era 5 python packaging setuptools
我正在研究一个跨平台的 Python 项目。它是一个带有 shell 自动完成功能的命令行工具,所以速度很重要。
setuptools生成控制台脚本的方式至少会产生 150 毫秒的开销 - 有时更多。这对于我正在编写的工具类型来说是完全不可接受的,考虑到它在基本情况下的作用很小,这应该是不必要的。
我正在尝试遵循现代 Python 项目的最佳实践,因此我正在使用它setuptools来构建项目。该包支持 windows,因此它能够为入口点生成二进制包装器是必不可少的。
无论我如何安装包 - 、、、 等pip install,都会发生这种情况。pip install -epip install --eggpython setup.py install
有一个讨论该问题的github问题,但目前还没有解决方法或解决方案。
在其他地方,我看到人们因此而回到 distutils,但这不是我的项目的选择。
我能想到的唯一解决方法是以某种方式扩展或自定义setuptools按项目安装时的功能,以便二进制垫片不使用pkg_resources.
如果没有这种相当激烈和没有建设性的措施,我还能做什么?
我的setup.py是基本的 - 大致如下:
import pip.req
import setuptools
def install_reqs():
reqs = pip.req.parse_requirements('requirements.txt', session=False)
reqs = [str(ir.req) for ir in reqs]
return reqs
setuptools.setup(
name='myproj',
version='v1.0.0-dev',
packages=setuptools.find_packages(exclude=('tests')),
install_requires=install_reqs(),
include_package_data=True,
entry_points={
'console_scripts': [
'myproj = myproj.cli.myproj:main',
]
},
)
Run Code Online (Sandbox Code Playgroud)
setuptools 为入口点生成的 shim 如下所示:
!$myhome/.venv/myproj/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'myproj==1.0.0.dev0','console_scripts','myproj'
__requires__ = 'myproj==1.0.0.dev0'
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.exit(
load_entry_point('myproj==1.0.0.dev0', 'console_scripts', 'myproj')()
)
Run Code Online (Sandbox Code Playgroud)
以下是cProfile使用 setuptools 生成的控制台脚本的一些统计信息:
ncalls tottime percall cumtime percall filename:lineno(function)
121/1 0.015 0.000 0.278 0.278 {built-in method builtins.exec}
1 0.000 0.000 0.278 0.278 myproj:3(<module>)
125/3 0.001 0.000 0.221 0.074 <frozen importlib._bootstrap>:966(_find_and_load)
125/3 0.001 0.000 0.221 0.074 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)
125/5 0.001 0.000 0.219 0.044 <frozen importlib._bootstrap>:659(_load_unlocked)
99/5 0.001 0.000 0.219 0.044 <frozen importlib._bootstrap_external>:656(exec_module)
152/4 0.000 0.000 0.218 0.054 <frozen importlib._bootstrap>:214(_call_with_frames_removed)
2 0.000 0.000 0.204 0.102 __init__.py:15(<module>)
32/15 0.000 0.000 0.135 0.009 {built-in method builtins.__import__}
1 0.000 0.000 0.088 0.088 __init__.py:540(load_entry_point)
1 0.000 0.000 0.085 0.085 __init__.py:2564(load_entry_point)
1 0.000 0.000 0.083 0.083 __init__.py:2216(load)
Run Code Online (Sandbox Code Playgroud)
这是一个没有 setuptools 垫片的自定义脚本:
ncalls tottime percall cumtime percall filename:lineno(function)
58/1 0.006 0.000 0.053 0.053 {built-in method builtins.exec}
1 0.000 0.000 0.053 0.053 test.py:1(<module>)
53/3 0.000 0.000 0.052 0.017 <frozen importlib._bootstrap>:966(_find_and_load)
53/3 0.000 0.000 0.052 0.017 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)
53/5 0.000 0.000 0.051 0.010 <frozen importlib._bootstrap>:659(_load_unlocked)
65/4 0.000 0.000 0.051 0.013 <frozen importlib._bootstrap>:214(_call_with_frames_removed)
45/5 0.000 0.000 0.051 0.010 <frozen importlib._bootstrap_external>:656(exec_module)
Run Code Online (Sandbox Code Playgroud)
自定义脚本 - test.py - 非常简单:
from myproj.cli.myproj import main
main()
Run Code Online (Sandbox Code Playgroud)
小智 0
如果我使用“pip install”从源代码安装项目,我也遇到过这个问题。但是,如果我先构建二进制 Wheel 文件,然后安装 Wheel,则生成的垫片似乎不会使用 pkg_resources 并且速度更快。我已经用 cookiecutter 项目对此进行了测试:
https://github.com/audreyr/cookiecutter
如果我克隆这个项目,然后使用原始方法“pip install”进行安装,生成的可执行脚本包含从 pkg_resources 的导入(并且速度很慢):
#!/usr/local/opt/python3/bin/python3.5
# EASY-INSTALL-ENTRY-SCRIPT: 'cookiecutter==1.5.1','console_scripts','cookiecutter'
__requires__ = 'cookiecutter==1.5.1'
import re
import sys
from pkg_resources import load_entry_point
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(
load_entry_point('cookiecutter==1.5.1', 'console_scripts', 'cookiecutter')()
)
Run Code Online (Sandbox Code Playgroud)
但是,如果我执行以下两个命令:
python setup.py bdist_wheel
pip install dist/cookiecutter-1.5.1-py2.py3-none-any.whl
Run Code Online (Sandbox Code Playgroud)
生成的 shim 不包含 pkg_resources (并且速度更快):
#!/usr/local/opt/python3/bin/python3.5
# -*- coding: utf-8 -*-
import re
import sys
from cookiecutter.__main__ import main
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
sys.exit(main())
Run Code Online (Sandbox Code Playgroud)
当我在 Windows 上尝试后一种方法时,它仍然创建了 .exe 填充程序。
| 归档时间: |
|
| 查看次数: |
435 次 |
| 最近记录: |