Je travaille sur un projet Python multiplateforme. Il s'agit d'un outil en ligne de commande avec autocomplétion de l'interpréteur de commandes, donc la vitesse est importante.
La manière setuptools
génère la console script impose au moins 150ms de surcharge - parfois plus. C'est tout simplement inacceptable pour le genre d'outil que j'écris, et ne devrait pas être nécessaire étant donné le peu qu'il fait dans le cas de base.
J'essaie de suivre les meilleures pratiques d'un projet Python moderne, et j'utilise donc setuptools
pour construire le projet. Le paquetage supporte Windows, donc sa capacité à générer des wrappers binaires pour les points d'entrée est essentielle.
Cela se produit quelle que soit la façon dont j'installe le paquet - pip install
, pip install -e
, pip install --egg
, python setup.py install
etc.
Il y a un numéro github discutant du problème, mais pas de solution de contournement ou de solution jusqu'à présent.
Ailleurs, j'ai vu des gens revenir à distutils pour cette raison, mais ce n'est pas une option pour mon projet.
La seule solution à laquelle je pense est d'étendre ou de personnaliser d'une manière ou d'une autre ce qui suit setuptools
fait quand il installe par projet pour que le shim binaire n'utilise pas pkg_resources
.
Que puis-je faire en dehors de cette mesure assez radicale et peu constructive ?
Mon setup.py
est basique - à peu près comme suit :
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',
]
},
)
La cale que setuptools génère pour le point d'entrée ressemble à ceci :
!$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')()
)
Voici quelques cProfile
stats en utilisant la console générée par setuptools script :
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)
Et le voici en tant que script personnalisé sans la cale 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)
Le script personnalisé - test.py - est très simple :
from myproj.cli.myproj import main
main()