2013-07-05 5 views
15

Sarebbe utile quando si distribuiscono le applicazioni per combinare tutte delle uova in un unico file zip in modo che tutto ciò che è necessario distribuire sia un singolo file zip e un file eseguibile (alcuni file binari personalizzati che si avvia semplicemente, carica il file zip principale funzione e lancia Python off o simili).Come puoi unire tutto il tuo codice Python in un unico file zip?

Ho visto parlare di fare questo in linea, ma nessun esempio di come farlo effettivamente.

Sono consapevole che è possibile (se protetto da zip) convertire le uova in file zip.

Quello che non sono sicuro circa è:

Si può combinare in qualche modo tutte le uova in un unico file zip? Se é cosi, come?

Come caricare ed eseguire il codice da un uovo specifico?

Come si garantisce che il codice in quell'uovo possa accedere a tutte le dipendenze (ad esempio altre uova nel file zip)?

Le persone chiedono questo tipo di materiale e ottengono risposte come; usa py2exe. Sì, ho capito, questa è una soluzione. Non è la domanda che sto chiedendo qui ...

+1

A tutti coloro che chiedono perché Zip, perché non va bene ecc. Ecc. Chiedi all'enorme comunità Java perché impacchettano tutto in JAR/WAR e sono ancora al top con awesomeness. La domanda è come ottenere un singolo bundle con python con codice e lib all'interno, che avrà solo bisogno di uno per avere Python installato e tutto funzionerà automaticamente. Ho una lista enorme di quando è necessario. –

risposta

21

È possibile automatizzare gran parte del lavoro con normali strumenti Python. Iniziamo con virtualenv pulito.

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

Ora installiamo un set di pacchetti che andranno nella libreria zippata. Il trucco è forzare l'installazione in una directory specifica.

(Nota: non utilizzare l'opzione --egg sia in linea di comando o in pip.conf/pip.ini perché si romperà layout di file che lo rende non-importabile in zip)

[[email protected] 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... 

Aggiornamento: pip ora ha lo switch -t <path>, che fa la stessa cosa di --install-option --install-lib=. Non

Ora cerchiamo di imballare tutti in uno zip

[[email protected] ziplib-demo]$ cd unpacked 
[[email protected] unpacked]$ ls 
waitress waitress-0.8.5-py2.7.egg-info 
[[email protected] 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%) 
[[email protected] unpacked]$ cd .. 

Si noti che questi file dovrebbero essere in cima alla zip, si può solo zip -r9 library.zip unpacked

Controllo del risultato:

[[email protected] 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>>> 

Aggiornamento: dal python 3.5 c'è anche zipapp module che può aiutare con il raggruppamento di tutto p ackage nel file .pyz. Per esigenze più complesse, , py2exe o py2app potrebbero essere più adatti alla bolletta.

0

È possibile utilizzare uno self-extracting zip file, impostato per avviare un interprete Python dopo aver decompresso le uova dallo stesso file .exe che le contiene.

1

Sì, un file zip/uovo può fornire più moduli, quindi è possibile combinarli in un unico file. Sono comunque molto scettico sul fatto che sia una buona idea. Hai ancora bisogno di installare quel file zip, e potrebbe ancora scontrarsi con altre versioni già installate, ecc.

Quindi la prima domanda da porsi è quale sia lo scopo. Perché vuoi un solo file? È per facilità di installazione, o facilità di distribuzione, o cosa?

Avere solo un file non renderà l'installazione più semplice, ci sono altri modi migliori. Puoi lasciare scaricare e installare automaticamente le dipendenze, è facile farlo.

E averli in un unico file zip significa comunque che è necessario espandere il file zip ed eseguire setup.py, che non è molto user-friendly.

Quindi avere un solo file non risolve molti problemi, quindi la domanda è quale problema si sta tentando di risolvere.

+0

Distribuzione specifica di un'applicazione pitone indipendente su un computer * senza python installato su di esso *; vale a dire. si crea un binario python personalizzato dall'origine che carica una stringa di avvio specifica (ad esempio "import blah; blah.main()") dopo aver importato il file zip nel percorso. Questo ti permette di distribuire un'intera app python come file binario + zip. Molto conveniente. Funziona bene; ma non quando hai dipendenze da librerie. – Doug

+0

Inoltre, scaricare automaticamente? Dato che pypi.python.org è rimasto fermo per ore questa settimana, direi che per una buona esperienza utente è un'idea spiacevole. Anche solo scaricando le cose quando si presentano risultati in timeout metà del tempo. Assolutamente non mi interessa andare in quella direzione. – Doug

0

Bene, è possibile creare i propri "pacchetti/uova" in {app-home-dir/pacchetti} (copiando le uova lì per esempio) e configurare file aggiuntivi in ​​setup.py (setuptools) per comprimerlo tutto come distribuzione singola (What is setup.py?). Nota che prima di avviare la funzione principale dell'app devi informare Python dove sono esattamente i tuoi "pacchetti/uova" esterni - aggiungendo {app-home-dir/packages} a sys.path. Questo è il modo semplice di creare un pacchetto standalone .. comunque con questo vanno i pericoli riguardo le dipendenze e le loro versioni, i moduli Python combinati con il codice Ansi C, ecc.

0

Riesci a combinare in qualche modo tutte le tue uova in un unico file zip? Se é cosi, come?

Sì, è possibile. Python caricherà dall'archivio zip che vengono aggiunti in sys.path (vedere PEP 273). Se metti tutte le librerie python in un archivio, l'archivio viene trattato come una directory. Questo è ciò che alcuni dei py2exe, bbfreeze, ecc.gli strumenti possono fare per isolare le librerie.

Per quanto riguarda il come, in realtà dipende da come sono installate le uova: pip, easy_install, ecc La logica sarebbe quella di controllare tutti voi le uova dipendenti e raccogliere il loro percorso di installazione e quindi zip le uova all'interno di un archivio.

Come caricare ed eseguire il codice da un uovo specifico?

È necessario definire il carico ed eseguire. Se stai parlando di importazione di moduli e pacchetti, non devi fare nulla di speciale . Ecco un post interessante sull'argomento, compreso qualche avvertimento Packaging Python programs as runnable ZIP files

Come si garantisce che il codice in quell'uovo possa accedere a tutte le dipendenze (ad esempio altre uova nel file zip)?

Questo è integrato purché le uova non siano estensioni (es. Zip safe). Vedi anche zipimport

+0

È manualmente l'ordinamento attraverso le uova e la copia delle sottocartelle è davvero l'unico modo? Non riesco a creare un singolo file zip con tutte le cartelle .egg in qualche modo? :( – Doug

+0

Inoltre, ho appena provato questo e non sembra funzionare, cioè installare blah, e creare un file zip da tutte le cartelle .egg e provare a importare; non funziona affatto. :(Can chiarisci il tuo terzo punto per caso? – Doug

2

Python eseguirà i file zip come se fossero singoli script se contengono un file __main __. Py [c] all'interno del livello superiore. Le importazioni dei pacchetti controlleranno anche all'interno del file zip che __main__ sta eseguendo dall'interno.

Quindi crea il tuo setup.py (py_modules = ['__main__'] qui è importante insieme a specificare tutti i tuoi pacchetti e altri moduli).

Quindi eseguire python setup.py bdist --format zip per creare il file zip. Ora se vuoi che sia eseguibile puoi fare quanto segue. A questo punto è possibile eseguire il file zip risultante come qualsiasi altro script python.

Un passo in più per gli utenti Linux/Mac lettura di questo per migliorare la convenienza (anche se probabilmente non lo scenario come si parla py2exe)

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

Questo antepone solo un #! linea al file zip in modo che quando viene eseguito dalla shell non è necessario specificare l'interprete. A questo punto è possibile eseguirlo come qualsiasi altro file binario sul sistema, anche se segretamente si tratta di un file zip pieno di python. Generalmente creo un makefile per eseguire setup.py e quindi eseguire questa conversione.

+0

Non dimenticare di creare il nuovo eseguibile zip: "chmod 555./my_executable_zip" o "chmod + x./my_executable_zip". –