web-dev-qa-db-fra.com

Comment pouvez-vous regrouper tout votre code python dans un seul fichier Zip?

Il serait pratique lors de la distribution d'applications de combiner tous des œufs dans un seul fichier Zip afin que tout ce que vous devez distribuer soit un seul fichier Zip et un exécutable (un binaire personnalisé qui démarre simplement, charge le Fonction principale du fichier Zip et coups de pied python off ou similaire).

J'ai vu parler de faire cela en ligne, mais aucun exemple de la façon de le faire.

Je suis conscient que vous pouvez (si son Zip est sûr) convertir des œufs en fichiers Zip.

Ce dont je ne suis pas sûr, c'est:

Pouvez-vous en quelque sorte combiner tous vos œufs dans un seul fichier Zip? Si c'est le cas, comment?

Comment charger et exécuter du code à partir d'un œuf spécifique?

Comment pourriez-vous vous assurer que le code de cet œuf pourrait accéder à toutes les dépendances (c'est-à-dire les autres œufs du fichier Zip)?

Les gens demandent beaucoup ce genre de choses et obtiennent des réponses comme; utilisez py2exe. Oui, je comprends, c'est une solution. Ce n'est pas la question que je pose ici ...

26
Doug

Vous pouvez automatiser la plupart du travail avec des outils python normaux. Commençons par virtualenv propre.

[zart@feena ~]$ mkdir ziplib-demo
[zart@feena ~]$ cd ziplib-demo
[zart@feena ziplib-demo]$ virtualenv .
New python executable in ./bin/python
Installing setuptools.............done.
Installing pip...............done.

Maintenant, installons un ensemble de packages qui iront dans la bibliothèque zippée. L'astuce consiste à forcer leur installation dans un répertoire spécifique.

(Remarque: n'utilisez pas l'option --Egg sur la ligne de commande ou dans pip.conf/pip.ini car cela briserait la mise en page du fichier le rendant non importable dans Zip)

[zart@feena ziplib-demo]$ bin/pip install --install-option --install-lib=$PWD/unpacked waitress
Downloading/unpacking waitress
  Downloading waitress-0.8.5.tar.gz (112kB): 112kB downloaded
  Running setup.py Egg_info for package waitress

Requirement already satisfied (use --upgrade to upgrade): setuptools in ./lib/python2.7/site-packages/setuptools-0.6c11-py2.7.Egg (from waitress)
Installing collected packages: waitress
  Running setup.py install for waitress

    Installing waitress-serve script to /home/zart/ziplib-demo/bin
Successfully installed waitress
Cleaning up...

Mise à jour : pip a maintenant -t <path> switch, cela fait la même chose que --install-option --install-lib=.

Maintenant, emballons-les tous dans un seul Zip

[zart@feena ziplib-demo]$ cd unpacked
[zart@feena unpacked]$ ls
waitress  waitress-0.8.5-py2.7.Egg-info
[zart@feena unpacked]$ Zip -r9 ../library.Zip *
  adding: waitress/ (stored 0%)
  adding: waitress/receiver.py (deflated 71%)
  adding: waitress/server.pyc (deflated 64%)
  adding: waitress/utilities.py (deflated 62%)
  adding: waitress/trigger.pyc (deflated 63%)
  adding: waitress/trigger.py (deflated 61%)
  adding: waitress/receiver.pyc (deflated 60%)
  adding: waitress/adjustments.pyc (deflated 51%)
  adding: waitress/compat.pyc (deflated 56%)
  adding: waitress/adjustments.py (deflated 60%)
  adding: waitress/server.py (deflated 68%)
  adding: waitress/channel.py (deflated 72%)
  adding: waitress/task.pyc (deflated 57%)
  adding: waitress/tests/ (stored 0%)
  adding: waitress/tests/test_regression.py (deflated 63%)
  adding: waitress/tests/test_functional.py (deflated 88%)
  adding: waitress/tests/test_parser.pyc (deflated 76%)
  adding: waitress/tests/test_trigger.pyc (deflated 73%)
  adding: waitress/tests/test_init.py (deflated 72%)
  adding: waitress/tests/test_utilities.pyc (deflated 78%)
  adding: waitress/tests/test_buffers.pyc (deflated 79%)
  adding: waitress/tests/test_trigger.py (deflated 82%)
  adding: waitress/tests/test_buffers.py (deflated 86%)
  adding: waitress/tests/test_runner.py (deflated 75%)
  adding: waitress/tests/test_init.pyc (deflated 69%)
  adding: waitress/tests/__init__.pyc (deflated 21%)
  adding: waitress/tests/support.pyc (deflated 48%)
  adding: waitress/tests/test_utilities.py (deflated 73%)
  adding: waitress/tests/test_channel.py (deflated 87%)
  adding: waitress/tests/test_task.py (deflated 87%)
  adding: waitress/tests/test_functional.pyc (deflated 82%)
  adding: waitress/tests/__init__.py (deflated 5%)
  adding: waitress/tests/test_compat.pyc (deflated 53%)
  adding: waitress/tests/test_receiver.pyc (deflated 79%)
  adding: waitress/tests/test_adjustments.py (deflated 78%)
  adding: waitress/tests/test_adjustments.pyc (deflated 74%)
  adding: waitress/tests/test_server.pyc (deflated 73%)
  adding: waitress/tests/fixtureapps/ (stored 0%)
  adding: waitress/tests/fixtureapps/filewrapper.pyc (deflated 59%)
  adding: waitress/tests/fixtureapps/getline.py (deflated 37%)
  adding: waitress/tests/fixtureapps/nocl.py (deflated 47%)
  adding: waitress/tests/fixtureapps/sleepy.pyc (deflated 44%)
  adding: waitress/tests/fixtureapps/echo.py (deflated 40%)
  adding: waitress/tests/fixtureapps/error.py (deflated 52%)
  adding: waitress/tests/fixtureapps/nocl.pyc (deflated 48%)
  adding: waitress/tests/fixtureapps/getline.pyc (deflated 32%)
  adding: waitress/tests/fixtureapps/writecb.pyc (deflated 42%)
  adding: waitress/tests/fixtureapps/toolarge.py (deflated 37%)
  adding: waitress/tests/fixtureapps/__init__.pyc (deflated 20%)
  adding: waitress/tests/fixtureapps/writecb.py (deflated 50%)
  adding: waitress/tests/fixtureapps/badcl.pyc (deflated 44%)
  adding: waitress/tests/fixtureapps/runner.pyc (deflated 58%)
  adding: waitress/tests/fixtureapps/__init__.py (stored 0%)
  adding: waitress/tests/fixtureapps/filewrapper.py (deflated 74%)
  adding: waitress/tests/fixtureapps/runner.py (deflated 41%)
  adding: waitress/tests/fixtureapps/echo.pyc (deflated 42%)
  adding: waitress/tests/fixtureapps/groundhog1.jpg (deflated 24%)
  adding: waitress/tests/fixtureapps/error.pyc (deflated 48%)
  adding: waitress/tests/fixtureapps/sleepy.py (deflated 42%)
  adding: waitress/tests/fixtureapps/toolarge.pyc (deflated 43%)
  adding: waitress/tests/fixtureapps/badcl.py (deflated 45%)
  adding: waitress/tests/support.py (deflated 52%)
  adding: waitress/tests/test_task.pyc (deflated 78%)
  adding: waitress/tests/test_channel.pyc (deflated 78%)
  adding: waitress/tests/test_regression.pyc (deflated 68%)
  adding: waitress/tests/test_parser.py (deflated 80%)
  adding: waitress/tests/test_server.py (deflated 78%)
  adding: waitress/tests/test_receiver.py (deflated 87%)
  adding: waitress/tests/test_compat.py (deflated 51%)
  adding: waitress/tests/test_runner.pyc (deflated 72%)
  adding: waitress/__init__.pyc (deflated 50%)
  adding: waitress/channel.pyc (deflated 58%)
  adding: waitress/runner.pyc (deflated 54%)
  adding: waitress/buffers.py (deflated 74%)
  adding: waitress/__init__.py (deflated 61%)
  adding: waitress/runner.py (deflated 58%)
  adding: waitress/parser.py (deflated 69%)
  adding: waitress/compat.py (deflated 69%)
  adding: waitress/buffers.pyc (deflated 69%)
  adding: waitress/utilities.pyc (deflated 60%)
  adding: waitress/parser.pyc (deflated 53%)
  adding: waitress/task.py (deflated 72%)
  adding: waitress-0.8.5-py2.7.Egg-info/ (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/dependency_links.txt (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/installed-files.txt (deflated 83%)
  adding: waitress-0.8.5-py2.7.Egg-info/top_level.txt (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/PKG-INFO (deflated 65%)
  adding: waitress-0.8.5-py2.7.Egg-info/not-Zip-safe (stored 0%)
  adding: waitress-0.8.5-py2.7.Egg-info/SOURCES.txt (deflated 71%)
  adding: waitress-0.8.5-py2.7.Egg-info/entry_points.txt (deflated 33%)
  adding: waitress-0.8.5-py2.7.Egg-info/requires.txt (deflated 5%)
[zart@feena unpacked]$ cd ..

Notez que ces fichiers doivent être en haut de Zip, vous ne pouvez pas simplement Zip -r9 library.Zip unpacked

Vérification du résultat:

[zart@feena ziplib-demo]$ PYTHONPATH=library.Zip python
Python 2.7.1 (r271:86832, Apr 12 2011, 16:15:16)
[GCC 4.6.0 20110331 (Red Hat 4.6.0-2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import waitress
>>> waitress
<module 'waitress' from '/home/zart/ziplib-demo/library.Zip/waitress/__init__.pyc'>
>>>
>>> from wsgiref.simple_server import demo_app
>>> waitress.serve(demo_app)
serving on http://0.0.0.0:8080
^C>>>

Mise à jour: depuis python 3.5 il y a aussi module zipapp qui peut aider à regrouper les paquet entier dans un fichier .pyz. Pour des besoins plus complexes pyinstaller , py2exe ou py2app pourrait mieux convenir.

37
Zart

Python exécutera les fichiers Zip comme s'il s'agissait de scripts uniques s'ils contiennent un fichier __main __. Py [c] à l'intérieur au niveau supérieur. Les importations de packages vérifieront également à l'intérieur du Zip que __main__ exécute de l'intérieur.

Créez donc votre setup.py (py_modules = ['__main__'] est important ici avec la spécification de tous vos packages et autres modules).

Exécutez ensuite python setup.py bdist --format Zip pour créer le fichier Zip. Maintenant, si vous voulez qu'il soit exécutable, vous pouvez faire ce qui suit. À ce stade, vous pouvez exécuter le fichier Zip résultant comme tout autre script python.

Une étape de plus pour les utilisateurs Linux/Mac lisant ceci pour améliorer la commodité (bien que ce ne soit probablement pas votre scénario car vous mentionnez py2exe)

echo '#!/usr/bin/env python' > my_executable_Zip
cat output_of_setup_py_bdist.Zip >> my_executable_Zip
chmod +x my_executable_Zip

Cela ajoute juste un #! ligne vers le fichier Zip de sorte que lors de l'exécution à partir du shell, vous n'avez pas besoin de spécifier l'interpréteur. À ce stade, vous pouvez l'exécuter comme n'importe quel autre binaire du système, bien qu'il s'agisse secrètement d'un fichier Zip plein de python. Je crée généralement un makefile pour exécuter setup.py, puis je fais cette conversion.

10
Matt

Vous pouvez utiliser le module zipapp de la bibliothèque standard pour créer des archives exécutables Python Zip. Il est disponible à partir de Python 3.5 et ultérieur).

Une façon de créer un bundle consiste à ajouter un fichier de niveau supérieur nommé __main__.py, qui sera le script qui Python s'exécute lorsque l'archive exécutable Zip est exécutée.

Supposons que votre structure de répertoire soit maintenant comme ceci:

└── myapp
    ├── __main__.py
    ├── myprog1.py
    └── myprog2.py

Si votre code a des dépendances externes (par exemple répertoriées dans un fichier nommé requirements.txt), installez-les dans le répertoire en utilisant:

pip3 install -r requirements.txt --target myapp/

note 1: Cela remplira le myapp/ répertoire avec les dépendances externes.

note 2: les utilisateurs de Debian/Ubuntu peuvent avoir besoin d'utiliser le --system option pour pip3, car la version Debian/Ubuntu de pip semble utiliser par défaut --user par défaut.

Ensuite, créez l'archive exécutable Zip en utilisant:

python3 -m zipapp myapp/

Cela créera une archive exécutable Zip nommée myapp.pyz, que vous pouvez exécuter en exécutant:

python3 myapp.pyz

Lorsque l'archive exécutable Zip est exécutée, il s'agit de __main__.py qui est exécuté.

Si, en plus des scripts Python, vous devez inclure d'autres fichiers de données utilisés par les scripts Python, voir: python: peut exécutable Zip les fichiers incluent des fichiers de données?

1
Flux

Oui, un fichier Zip/Egg peut fournir plusieurs modules, vous pouvez donc les combiner en un seul fichier. Je suis cependant très sceptique à l'idée que ce soit une bonne idée. Vous devez toujours installer ce fichier Zip, et il peut toujours entrer en conflit avec d'autres versions déjà installées, etc.

La première question à se poser est donc quel est le but. Pourquoi voulez-vous un seul fichier? Est-ce pour la facilité d'installation, la facilité de distribution ou quoi?

Avoir un seul fichier ne facilitera pas vraiment l'installation, il existe d'autres moyens plus efficaces. Vous pouvez laisser l'installation télécharger et installer les dépendances automatiquement, c'est facile à faire.

Et les avoir dans un seul fichier Zip signifie que vous devez étendre ce fichier Zip et exécuter setup.py, ce qui n'est pas très convivial.

Donc, avoir un seul fichier ne résout pas vraiment beaucoup de problèmes, donc la question est de savoir quel problème vous essayez de résoudre.

1
Lennart Regebro

Eh bien, il est possible de créer vos propres "packages/eggs" dans votre {app-home-dir/packages} (en y copiant des oeufs par exemple) et de configurer des fichiers supplémentaires dans setup.py (setuptools) pour tout emballer en une seule distribution ( Qu'est-ce que setup.py? ). Notez qu'avant de lancer la fonction principale de votre application, vous devez informer Python où se trouvent exactement vos "packages/eggs" externes - en ajoutant {app-home-dir/packages} à sys.path C'est le moyen le plus simple de créer un package autonome .. cependant cela entraîne des dangers concernant les dépendances et leurs versions, Python mélangés avec du code Ansi C, etc.

0
soerium

Pouvez-vous en quelque sorte combiner tous vos œufs dans un seul fichier Zip? Si oui, comment?

Oui, vous pouvez. Python se chargera à partir des archives Zip qui sont ajoutées dans sys.path (voir PEP 27 ). Si vous mettez toutes les bibliothèques python à l'intérieur d'une archive, l'archive est traitée comme un répertoire, c'est ce que certains des outils py2exe, bbfreeze, etc. peuvent faire pour isoler les bibliothèques.

En ce qui concerne le comment, cela dépend vraiment de la façon dont vos œufs sont installés: pip, easy_install, etc. La logique serait d'inspecter tous les œufs dépendants et de rassembler leur chemin d'installation, puis de compresser les œufs dans une archive.

Comment charger et exécuter du code à partir d'un œuf spécifique?

Vous devez définir la charge et l'exécution. Si vous parlez d'importer des modules et des packages, vous n'avez rien à faire de spécial. Voici un article de blog intéressant sur le sujet, y compris quelques mises en garde Packaging Python programmes en fichiers Zip exécutables

Comment vous assureriez-vous que le code dans lequel Egg pourrait accéder à toutes les dépendances (c.-à-d. D'autres œufs dans le fichier Zip)?

Ceci est intégré tant que les oeufs ne sont pas des extensions (c'est-à-dire Zip safe). Voir aussi zipimport

0
Rod

Vous pouvez utiliser un fichier Zip auto-extractible , configuré pour lancer un interpréteur Python après avoir décompressé les œufs à partir du même fichier .exe qui les contient).

0
John Zwinck