Je travaille sur un projet Python multiplateforme. C'est un outil en ligne de commande avec une auto-complétion de shell, donc la rapidité est importante.
La façon dont setuptools
génère le script console impose au moins un surcoût de 150 ms - parfois plus. C'est tout simplement inacceptable pour le type d'outil que je suis en train d'écrire, et cela ne devrait pas être nécessaire étant donné ce qu'il fait dans le cas de base.
J'essaie de suivre les meilleures pratiques pour un projet Python moderne, c'est pourquoi j'utilise setuptools
pour construire le projet. Le package prend en charge Windows, donc sa capacité à générer des wrappers binaires pour les points d'entrée est essentielle.
Cela se produit indépendamment de la manière dont j'installe le package - pip install
, pip install -e
, pip install --egg
, python setup.py install
, etc.
Il y a un problème github qui discute du problème, mais pour l'instant, il n'y a pas de solution ou de contournement.
Ailleurs, j'ai vu des gens revenir à distutils à cause de cela, mais ce n'est pas une option pour mon projet.
Le seul contournement auquel je pense est d'une manière ou d'une autre étendre ou personnaliser ce que setuptools
fait lors de l'installation de mon projet afin que le shim binaire n'utilise pas pkg_resources
.
Que puis-je faire en dehors de cette mesure assez drastique et non constructive ?
Mon setup.py
est basique - approximativement 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',
]
},
)
Le shim que génère setuptools 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 statistiques de cProfile
en utilisant le script console généré par 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()
125/3 0.001 0.000 0.221 0.074 :966(_find_and_load)
125/3 0.001 0.000 0.221 0.074 :939(_find_and_load_unlocked)
125/5 0.001 0.000 0.219 0.044 :659(_load_unlocked)
99/5 0.001 0.000 0.219 0.044 :656(exec_module)
152/4 0.000 0.000 0.218 0.054 :214(_call_with_frames_removed)
2 0.000 0.000 0.204 0.102 __init__.py:15()
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 le shim de 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()
53/3 0.000 0.000 0.052 0.017 :966(_find_and_load)
53/3 0.000 0.000 0.052 0.017 :939(_find_and_load_unlocked)
53/5 0.000 0.000 0.051 0.010 :659(_load_unlocked)
65/4 0.000 0.000 0.051 0.013 :214(_call_with_frames_removed)
45/5 0.000 0.000 0.051 0.010 :656(exec_module)
Le script personnalisé - test.py - est très simple :
from myproj.cli.myproj import main
main()