Comment conditionner un projet Python avec toutes ses dépendances pour une installation hors connexion.

J'écris cet article pour montrer que je pense que c'est la bonne façon d'installer et de conditionner des applications python avec toutes leurs dépendances.

Vous avez souvent besoin d'un package que vous pouvez utiliser pour installer l'application et ses dépendances sans même accéder à Internet. Il peut s'agir d'un serveur distant doté d'un accès au réseau interne uniquement, pour des raisons de sécurité, et l'une de vos dépendances peut-être. est hébergé sur un référentiel privé git et vous ne souhaitez pas coder en dur le jeton git pour l'installer via https, par exemple, un conteneur docker.

Mon approche consiste à combiner SetupTools, DistUtils et pip Wheel pour un format final tar.gz.

Je suppose que vous connaissez déjà les bases de l'emballage:
https://python-packaging.readthedocs.io/en/latest/minimal.html

L’emballage de base de Python nécessite au minimum un fichier setup.py à la racine de votre projet, que vous pourrez ensuite appeler sur python setup.py sdist.

setup.py gist

La cmdclass est une extension de setuptools et est la classe qui conditionnera le code pour la distribution, mais collectera également tous les packages de Requirements.txt dans l'archive.
Ce script ci-dessous (package.py) est une extension de commande setuptools permettant de créer une distribution à partir d'un projet.
sdist d’installation normale en python ne compresse que les fichiers et les dossiers,
exigences.txt fera une roue
(zip comme archive) de la nécessité d’être stocké dans le dossier de la timonerie et emballé avec
le code en tant que fichier tar.gz unique.

Mise en garde sur l'emballage:
Ce script collecte les exigences installées (compilées) à partir de leur lieu d'exécution, ce qui signifie que si votre exigence.txt contient des exigences basées sur des extensions C, telles que psycopg, par exemple, le package compilé sera collecté.
Lorsque vous décompressez l'archive de la destination si le système est différent de celui sur lequel vous avez récupéré le paquet, celui-ci ne fonctionnera pas comme prévu et même tombera en panne.

laissez-moi répéter ceci:
ubuntu! = centos! = macOS
python2.6! = ​​python2.7

Vous pouvez toutefois créer un paquet sur ubuntu lorsque le système cible est Debian car ils appartiennent à la même famille.

package.py gist

Ce script ne peut s’exécuter que dans la même famille car des extensions C doivent être compilées sur des
plate-forme (psycopg, etc.).

Ce que fait ce script:

Ce script supprime et recrée le dossier de la timonerie à la racine de votre répertoire de projet.

Il appelle ensuite pip wheel -r Requirements.txt qui collecte les packages installés à partir de l’environnement actuel dans lequel ils sont installés. Le script crée un fichier local require.txt sans aucun lien http, uniquement le package local. nom comme il est stocké dans la timonerie, la raison en est la façon dont fonctionne pip.

Une fois le package décompressé à la destination cible, les exigences peuvent être installées localement et hors ligne à partir du dossier Wheelhouse à l'aide de l'option --no-index on pip install qui ignore l'index du package (en recherchant uniquement les URL --find-links.).
--find-links recherche l'archive à partir de l'URL ou du chemin.

Etant donné que les exigences originales.txt pourraient avoir des liens vers un dépôt non-pip tel que Github (https), pip analysera les liens de l'archive à partir d'une URL et non de la timonerie, ce qui entraînera une requête http.

Cette fonction crée un nouveau quota.txt (il sauvegardera le fichier Requirements.txt d'origine dans Requirements.orig et restaurera après le conditionnement) avec uniquement le nom et la version de chacun des packages, éliminant ainsi la nécessité d'extraire / analyser des liens. sources http et installer toutes les archives complètement hors ligne depuis la timonerie.

Enfin, le script appelle setuptools sdist - vous pouvez donc le modifier dans le format de votre choix pris en charge par setuptools.

MANIFEST.in
La dernière partie de l’emballage de la timonerie consiste à indiquer à setuptools d’inclure ce dossier dans les archives à l’aide de la greffe:

MANIFEST.in gist

Notez que je taille (supprime / saute de l’archive) le dossier git lui-même.

Mettre tous ensemble:
Créez les fichiers à la racine de votre projet:

  • package.py
  • setup.py
  • MANIFEST.in

Appelez le package setup.py de python:
cela supprimera et recréera le dossier de la timonerie à la racine de votre projet, puis il rassemblera les colis dans le dossier de la timonerie.
La dernière étape créera l’archive dans le dossier dist à la racine de votre projet.

À ce stade, vous pouvez copier l'archive dans une image de menu fixe ou sur votre serveur comme bon vous semble.

Déballage:
Pour décompresser simplement tar zxf archive.tar.gz puis appeler

pip install -r requirements.txt --use-wheel --no-index - timonerie Find-Links

vos paquets seront installés complètement hors ligne.

Astuce Bonus:
Si vous envisagez d'exécuter cette archive dans un conteneur Docker, je vous suggère de construire une image Python Docker avec toutes les bibliothèques gcc OpenSSL et autres pour installer toutes les dépendances sur et à partir de ce conteneur. Exécuter le package setup.py dans un volume de montage / copie partagé. où tu veux. Ainsi, votre conteneur d’exécution est maigre et n’a pas besoin de toutes les bibliothèques de construction lourdes.