zipapp
--- Manage executable Python zip archives¶
Ajouté dans la version 3.5.
Code source : Lib/zipapp.py
Ce module fournit des outils pour gérer la création de fichiers zip contenant du code Python, qui peuvent être exécutés directement par l'interpréteur Python. Le module fournit à la fois une interface de ligne de commande Interface en ligne de commande et une interface API Python.
Exemple de base¶
L'exemple suivant montre comment l'interface de ligne de commande Interface en ligne de commande peut être utilisée pour créer une archive exécutable depuis un répertoire contenant du code Python. Lors de l'exécution, l'archive exécutera la fonction main
du module myapp
dans l'archive.
$ python -m zipapp myapp -m "myapp:main"
$ python myapp.pyz
<output from myapp>
Interface en ligne de commande¶
Lorsqu'il est appelé en tant que programme à partir de la ligne de commande, la syntaxe suivante est utilisée :
$ python -m zipapp source [options]
Si source est un répertoire, une archive est créée à partir du contenu de source. Si source est un fichier, ce doit être une archive et il est copié dans l'archive cible (ou le contenu de sa ligne shebang est affiché si l'option --info
est indiquée).
Les options suivantes sont disponibles :
- -o <output>, --output=<output>¶
Écrit la sortie dans un fichier nommé output. Si cette option n'est pas spécifiée, le nom du fichier de sortie sera le même que celui de l'entrée source, avec l'extension
.pyz
. Si un nom de fichier explicite est donné, il est utilisé tel quel (une extension.pyz
doit donc être incluse si nécessaire).Un nom de fichier de sortie doit être spécifié si la source est une archive (et, dans ce cas, la sortie ne doit pas être la même que la source).
- -p <interpreter>, --python=<interpreter>¶
Ajoute une ligne
#!
à l'archive en spécifiant interpreter comme commande à exécuter. Aussi, sur un système POSIX, cela rend l'archive exécutable. Le comportement par défaut est de ne pas écrire la ligne#!
et de ne pas rendre le fichier exécutable.
- -m <mainfn>, --main=<mainfn>¶
Écrit un fichier
__main__.py
dans l'archive qui exécute mainfn. L'argument mainfn est de la forme « pkg.mod:fn », où « pkg.mod » est un paquet/module dans l'archive, et « fn » est un appelable dans le module donné. Le fichier__main__.py
réalise cet appel.--main
ne peut pas être spécifié lors de la copie d'une archive.
- -c, --compress¶
Compresse les fichiers avec la méthode deflate, réduisant ainsi la taille du fichier de sortie. Par défaut, les fichiers sont stockés non compressés dans l'archive.
--compress
n'a aucun effet lors de la copie d'une archive.Ajouté dans la version 3.7.
- --info¶
Affiche l'interpréteur intégré dans l'archive, à des fins de diagnostic. Dans ce cas, toutes les autres options sont ignorées et SOURCE doit être une archive et non un répertoire.
- -h, --help¶
Affiche un court message d'aide et quitte.
API Python¶
Ce module définit deux fonctions utilitaires :
- zipapp.create_archive(source, target=None, interpreter=None, main=None, filter=None, compressed=False)¶
Crée une archive d'application à partir de source. La source peut être de natures suivantes :
Le nom d'un répertoire, ou un path-like object se référant à un répertoire ; dans ce cas, une nouvelle archive d'application sera créée à partir du contenu de ce répertoire.
Le nom d'un fichier d'archive d'application existant, ou un path-like object se référant à un tel fichier ; dans ce cas, le fichier est copié sur la cible (en le modifiant pour refléter la valeur donnée à l'argument interpreter). Le nom du fichier doit inclure l'extension
.pyz
, si nécessaire.Un objet fichier ouvert pour la lecture en mode binaire. Le contenu du fichier doit être une archive d'application et Python suppose que l'objet fichier est positionné au début de l'archive.
L'argument target détermine où l'archive résultante sera écrite :
S'il s'agit d'un nom de fichier, ou d'un path-like object, l'archive sera écrite dans ce fichier.
S'il s'agit d'un objet fichier ouvert, l'archive sera écrite dans cet objet fichier, qui doit être ouvert pour l'écriture en mode octets.
Si la cible est omise (ou
None
), la source doit être un répertoire et la cible sera un fichier portant le même nom que la source, avec une extension.pyz
ajoutée.
L'argument interpreter spécifie le nom de l'interpréteur Python avec lequel l'archive sera exécutée. Il est écrit dans une ligne shebang au début de l'archive. Sur un système POSIX, cela est interprété par le système d'exploitation et, sur Windows, il sera géré par le lanceur Python. L'omission de l'interpreter n'entraîne pas l'écriture d'une ligne shebang. Si un interpréteur est spécifié et que la cible est un nom de fichier, le bit exécutable du fichier cible sera mis à 1.
L'argument main spécifie le nom d'un appelable, utilisé comme programme principal pour l'archive. Il ne peut être spécifié que si la source est un répertoire et si la source ne contient pas déjà un fichier
__main__.py
. L'argument main doit prendre la formepkg.module:callable
et l'archive sera exécutée en importantpkg.module
et en exécutant l'appelable donné sans argument. Omettre main est une erreur si la source est un répertoire et ne contient pas un fichier__main__.py
car, dans ce cas, l'archive résultante ne serait pas exécutable.L'argument optionnel filter spécifie une fonction de rappel à laquelle on passe un objet Path représentant le chemin du fichier à ajouter (par rapport au répertoire source). Elle doit renvoyer
True
si le fichier doit effectivement être ajouté.L'argument optionnel compressed détermine si les fichiers doivent être compressés. S'il vaut
True
, les fichiers de l'archive sont compressés avec l'algorithme deflate ; sinon, les fichiers sont stockés non compressés. Cet argument n'a aucun effet lors de la copie d'une archive existante.Si un objet fichier est spécifié pour source ou target, il est de la responsabilité de l'appelant de le fermer après avoir appelé
create_archive
.Lors de la copie d'une archive existante, les objets fichier fournis n'ont besoin que des méthodes
read
etreadline
ouwrite
. Lors de la création d'une archive à partir d'un répertoire, si la cible est un objet fichier, elle sera passée à la classezipfile.ZipFile
et devra fournir les méthodes nécessaires à cette classe.Modifié dans la version 3.7: Added the filter and compressed parameters.
- zipapp.get_interpreter(archive)¶
Renvoie l'interpréteur spécifié dans la ligne
#!
au début de l'archive. S'il n'y a pas de ligne#!
, renvoieNone
. L'argument archive peut être un nom de fichier ou un objet de type fichier ouvert à la lecture en mode binaire. Python suppose qu'il est au début de l'archive.
Exemples¶
Regroupe le contenu d'un répertoire dans une archive, puis l'exécute.
$ python -m zipapp myapp
$ python myapp.pyz
<output from myapp>
La même chose peut être faite en utilisant la fonction create_archive()
:
>>> import zipapp
>>> zipapp.create_archive('myapp', 'myapp.pyz')
Pour rendre l'application directement exécutable sur un système POSIX, spécifiez un interpréteur à utiliser.
$ python -m zipapp myapp -p "/usr/bin/env python"
$ ./myapp.pyz
<output from myapp>
Pour remplacer la ligne shebang sur une archive existante, créez une archive modifiée en utilisant la fonction create_archive()
:
>>> import zipapp
>>> zipapp.create_archive('old_archive.pyz', 'new_archive.pyz', '/usr/bin/python3')
To update the file in place, do the replacement in memory using a BytesIO
object, and then overwrite the source afterwards. Note that there is a risk
when overwriting a file in place that an error will result in the loss of
the original file. This code does not protect against such errors, but
production code should do so. Also, this method will only work if the archive
fits in memory:
>>> import zipapp
>>> import io
>>> temp = io.BytesIO()
>>> zipapp.create_archive('myapp.pyz', temp, '/usr/bin/python2')
>>> with open('myapp.pyz', 'wb') as f:
>>> f.write(temp.getvalue())
Spécification de l'interprète¶
Notez que si vous spécifiez un interpréteur et que vous distribuez ensuite votre archive d'application, vous devez vous assurer que l'interpréteur utilisé est portable. Le lanceur Python pour Windows gère la plupart des formes courantes de la ligne POSIX #!
, mais il y a d'autres problèmes à considérer :
Si vous utilisez
/usr/bin/env python
(ou d'autres formes de la commande python, comme/usr/bin/python
), vous devez considérer que vos utilisateurs peuvent avoir Python 2 ou Python 3 par défaut, et écrire votre code pour fonctionner dans les deux versions.Si vous utilisez une version explicite, par exemple
/usr/bin/env python3
votre application ne fonctionnera pas pour les utilisateurs qui n'ont pas cette version. (C'est peut-être ce que vous voulez si vous n'avez pas rendu votre code compatible Python 2).Il n'y a aucun moyen de dire « python X.Y ou supérieur » donc faites attention si vous utilisez une version exacte comme
/usr/bin/env python3.4
car vous devrez changer votre ligne shebang pour les utilisateurs de Python 3.5, par exemple.
Normalement, vous devriez utiliser un /usr/bin/env python2
ou /usr/bin/env python3
, selon que votre code soit écrit pour Python 2 ou 3.
Création d'applications autonomes avec zipapp¶
En utilisant le module zipapp
, il est possible de créer des programmes Python qui peuvent être distribués à des utilisateurs finaux dont le seul pré-requis est d'avoir la bonne version de Python installée sur leur ordinateur. Pour y arriver, la clé est de regrouper toutes les dépendances de l'application dans l'archive avec le code source de l'application.
Les étapes pour créer une archive autonome sont les suivantes :
Créez votre application dans un répertoire comme d'habitude, de manière à avoir un répertoire
myapp
contenant un fichier__main__.py
et tout le code de l'application correspondante.Installez toutes les dépendances de votre application dans le répertoire
myapp
en utilisant pip :$ python -m pip install -r requirements.txt --target myapp
(ceci suppose que vous ayez vos dépendances de projet dans un fichier
requirements.txt
— sinon vous pouvez simplement lister les dépendances manuellement sur la ligne de commande pip).Regroupez le tout à l'aide de :
$ python -m zipapp -p "interpreter" myapp
Cela produira un exécutable autonome qui peut être exécuté sur n'importe quelle machine avec l'interpréteur approprié disponible. Voir Spécification de l'interprète pour plus de détails. Il peut être envoyé aux utilisateurs sous la forme d'un seul fichier.
Sous Unix, le fichier myapp.pyz
est exécutable tel quel. Vous pouvez renommer le fichier pour supprimer l'extension .pyz
si vous préférez un nom de commande « simple ». Sous Windows, le fichier myapp.pyz[w]
est exécutable en vertu du fait que l'interpréteur Python est associé aux extensions de fichier .pyz
et .pyzw
une fois installé.
Mises en garde¶
Si votre application dépend d'un paquet qui inclut une extension C, ce paquet ne peut pas être exécuté à partir d'un fichier zip (c'est une limitation du système d'exploitation, car le code exécutable doit être présent dans le système de fichiers pour que le lanceur de l'OS puisse le charger). Dans ce cas, vous pouvez exclure cette dépendance du fichier zip et, soit demander à vos utilisateurs de l'installer, soit la fournir avec votre fichier zip et ajouter du code à votre fichier __main__.py
pour inclure le répertoire contenant le module décompressé dans sys.path
. Dans ce cas, vous devrez vous assurer d'envoyer les binaires appropriés pour votre ou vos architecture(s) cible(s) (et éventuellement choisir la bonne version à ajouter à sys.path
au moment de l'exécution, basée sur la machine de l'utilisateur).
Le format d'archive d'application Zip Python¶
Python est capable d'exécuter des fichiers zip qui contiennent un fichier __main__.py
depuis la version 2.6. Pour être exécutée par Python, une archive d'application doit simplement être un fichier zip standard contenant un fichier __main__.py
qui sera exécuté comme point d'entrée de l'application. Comme d'habitude pour tout script Python, le parent du script (dans ce cas le fichier zip) sera placé sur sys.path
et ainsi d'autres modules pourront être importés depuis le fichier zip.
Le format de fichier zip permet d'ajouter des données arbitraires à un fichier zip. Le format de l'application zip utilise cette possibilité pour préfixer une ligne shebang POSIX standard dans le fichier (#!/path/to/interpreter
).
Formellement, le format d'application zip de Python est donc :
An optional shebang line, containing the characters
b'#!'
followed by an interpreter name, and then a newline (b'\n'
) character. The interpreter name can be anything acceptable to the OS "shebang" processing, or the Python launcher on Windows. The interpreter should be encoded in UTF-8 on Windows, and insys.getfilesystemencoding()
on POSIX.Des données zipfile standards, telles que générées par le module
zipfile
. Le contenu du fichier zip doit inclure un fichier appelé__main__.py
(qui doit se trouver à la racine du fichier zip — c'est-à-dire qu'il ne peut se trouver dans un sous-répertoire). Les données du fichier zip peuvent être compressées ou non.
Si une archive d'application a une ligne shebang, elle peut avoir le bit exécutable activé sur les systèmes POSIX, pour lui permettre d'être exécutée directement.
Vous pouvez créer des archives d'applications sans utiliser les outils de ce module — le module existe pour faciliter les choses, mais les archives, créées par n'importe quel moyen tout en respectant le format ci-dessus, sont valides pour Python.