Empaquetage des projets Python pour Debian / Raspbian avec dh-virtualenv

Cet article a pour but d'expliquer certaines choses aux développeurs qui n'utilisent pas beaucoup Python et qui pourraient avoir des difficultés avec certains concepts.

Je recommande vivement la lecture de l'article suivant comme introduction aux concepts abordés ici :

pypi.org

pypi.org est un dépôt officiel de logiciels pour le langage de programmation Python. Il comprend des bibliothèques que nous voulons utiliser dans nos projets, mais qui ne sont pas livrées par défaut avec Python.

Le problème

Notre objectif est d'empaqueter une application écrite en Python (ciblant Python3) sous forme de paquet .deb pour Raspbian (qui est, tout bien considéré, vraiment équivalent à Debian).

Notre application a des dépendances sur plusieurs bibliothèques Python.

Par exemple, nous aimerions utiliser le demande bibliothèque. La bibliothèque requests elle-même dépend d'autres bibliothèques, par exemple chardet, urllib3, etc.

La gestion manuelle de ces dépendances et l'envoi manuel du code de bibliothèque requis sont intrinsèquement peu pratiques.

pip

Python possède son propre système de gestion des paquets et des dépendances, appelé pip

pip vous permet d'installer des bibliothèques et des applications python, afin que votre propre code puisse utiliser ces bibliothèques.

Ici, il y a deux problèmes :

  • nous voulons expédier le paquet comme un Paquet Debianpour que les utilisateurs finaux puissent les installer facilement. Nous pouvons supposer que sur un nombre significatif de systèmes cibles, les bibliothèques python appropriées n'auront pas été installées par l'utilisateur.
  • si nous essayons d'installer ces bibliothèques à l'échelle du système au nom de l'utilisateurnous risquons de rompre la compatibilité avec d'autres paquets (par exemple, en raison de changements d'API entre les versions des bibliothèques).

Nous avons donc besoin d'une solution.

virtualenv

virtualenv nous permettra de créer des environnements virtuels pour Python.

Dans ces environnements virtuels, nous avons :

  • notre propre interpréteur Python
  • des copies des bibliothèques standard requises
  • notre propre tuyau
  • notre propre bibliothèque "à l'échelle du système

Partie pratique : Essai de virtualenv

Installez virtualenv (dans le cadre de dh-virtualenv, que nous aborderons dans un moment) en faisant :

sudo apt install dh-virtualenv

Comme les requêtes sont déjà installées dans tout le système sur ma boîte de test, nous allons utiliser un paquet différent comme exemple. randstr vous permettra de générer une chaîne aléatoire.

Vérifiez si randstr est installé dans tout le système :

pip3 show randstr

Cela ne devrait rien donner. Indiquant que ce paquet n'est pas installé dans tout le système :

image

Nous allons maintenant créer un environnement virtuel. Le dossier de l'environnement virtuel ne doit PAS nécessairement se trouver à l'intérieur de votre dossier de code, mais il le peut. Vous devriez l'ignorer dans GIT.

disons que nous avons un répertoire /home/pi/tutorial

Passez dans ce répertoire, et créez un nouveau dossier d'environnement env :

cd /home/pi/tutorial

quel python3

virtualenv -p /usr/bin/python3 env

Note : vous devez spécifier l'interpréteur Python si vous voulez Python 3, car sinon Python 2 sera utilisé. J'utilise Python 3. (Exécution de virtualenv avec l'interpréteur /usr/bin/python2)

which python3 vous dira où réside le binaire python3, ajustez le chemin pour virtualenv en conséquence.

image

activer l'environnement :

source env/bin/activate

(Ce chemin de commande suppose que vous êtes resté dans le répertoire du tutoriel). Veuillez également noter qu'il ne s'agit pas d'un script exécutable - vous devez utiliser la commande source pour l'utiliser avec votre terminal bash.

Remarquez, comment (env) est ajouté avant votre invite de commande :

image

Cela signifie que l'environnement est actif. Maintenant vous pouvez relancer pip3, mais cette fois-ci pip3 va effectuer son travail sur l'environnement virtuel :

pip3 show randstr

demandes de spectacles pip3

ne devrait toujours rien donner. La deuxième ligne ne donnera également rien - ce qui montre que (si les demandes sont installées dans tout le système) nous sommes bien dans un environnement virtuel.

Maintenant, installez randstr :

pip3 install randstr

et vérifiez à nouveau, s'il est installé :

pip3 show randstr

image

Cette fois, il montre que randstr est installé. Il a été installé dans env/lib/python3.5/site-packages :

image

Pendant que l'environnement est encore activé, écrivons un petit exemple d'application Python :

nano sample.py

collez le code suivant, générant une chaîne aléatoire en utilisant la nouvelle bibliothèque que nous venons d'installer :

from randstr import randstr
print("hello world")
print(randstr())

et sauvegarder.

Exécutez le code en utilisant python3 :

python3 sample.py

tant que l'environnement est encore actif, cela fonctionnera :

image

Il est maintenant temps de quitter l'environnement, pour voir si le code s'exécute toujours :

désactiver

Votre promptitude va revenir à la normale. Et

python3 sample.py

affichera un message d'erreur, indiquant qu'aucun module 'randstr' n'existe sur votre système. C'est exactement le comportement que nous voulons !

image

Vous pouvez jeter un coup d'oeil au dossier env, pour voir comment il fournit toutes les choses nécessaires pour exécuter votre code Python, y compris les bibliothèques, l'exécutable python, pip, et plus encore.

Empaquetage de virtualenv Debian avec dh-virtualenv

OK, maintenant que les bases sont posées, ce que nous voulons, c'est empaqueter un virtualenv avec notre code, afin que notre application fonctionne de manière fiable et sans perturber les autres applications sur les ordinateurs de nos utilisateurs.

C'est là que dh-virtualenv dh-virtualenv est un ajout aux scripts de construction de Debian, qui vous permet d'empaqueter des environnements virtuels.

Nous devons créer une structure de base pour notre nouveau paquet. C'est là que emporte-pièce vous aidera.

emporte-pièce

cookiecutter crée pour vous de nouveaux projets à partir de modèles, ce qui réduit les frais généraux et le temps que vous consacrez au développement et à la compréhension des nombreux fichiers nécessaires.

https://cookiecutter.readthedocs.io/en/latest/

sudo apt install cookiecutter

Note : le paquet python3-cookiecutter fournira un module Python pour Python 3. Ce que nous voulons, c'est l'application elle-même, qui est installée avec le paquet cookiecutter, comme indiqué ci-dessus. Cela pourrait tirer dans Python 2, mais - oh bien.

cookiecutter n'est pas nécessaire pour vos utilisateurs finaux, il est seulement utilisé pour créer plusieurs fichiers pour votre paquet.

créer un répertoire de projet exemple, dans lequel nous allons appliquer le modèle (je suis toujours dans le répertoire tutorial) :

mkdir sampleproject

cd sampleproject

En utilisant un moule spécial pour dh-virtualenv nous pouvons configurer plusieurs des fichiers nécessaires :

https://github.com/Springerle/dh-virtualenv-mold

emporte-pièce https://github.com/Springerle/dh-virtualenv-mold.git

Cela vous posera plusieurs questions.

image

Notez que le dossier doit être nommé debian, même si vous empaquetez pour Raspbian - gardez donc le nom debian.

Cela va installer les fichiers suivants :

image

Maintenant vous devez exécuter les commandes suivantes, selon les instructions sous le dh-virtualenv-mold :

sudo apt-get install build-essential debhelper devscripts equivs
sudo mk-build-deps --install debian/control
Pour construire le paquet plus tard, vous devez exécuter la commande suivante à partir du répertoire de premier niveau de votre projet :
dpkg-buildpackage -uc -us -b
Pour l'instant, cependant, la commande échouera parce que setup.py est manquant. Nous arriverons à setup.py et requirements.txt dans un court instant :
/usr/bin/python3 : Impossible d'ouvrir le fichier 'setup.py' : [Errno 2] Pas de tel fichier ou répertoire

Informations sur les dossiers individuels

journal des modifications

Ce fichier contiendra les informations sur la version du paquet. Vous pouvez le mettre à jour à l'aide d'un outil spécial, dch.

Ce fichier n'est pas un journal des modifications de votre application, mais simplement un journal des modifications de l'emballage de votre application.

compat

Ce fichier comprend un chiffre magique spécial "9". (pour des questions de compatibilité, il est bon de le laisser tel quel)

contrôle

C'est le fichier principal pour définir les paramètres des paquets et les dépendances au niveau de Debian. Si votre application dépend, par exemple, de l'installation d'omxplayer, il faudra l'indiquer ici en tant que dépendance :

Source : projet pilote
Section : contrib/python
Priorité : supplémentaire
Mainteneur : Maximilian Batz
Compatibilité : debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
Standards-Version : 3.9.5
Page d'accueil :
https://picockpit.com


Paquet : sampleproject
Architecture : toute
Prédépendants : dpkg (>= 1.16.1), python2.7 | python3, ${misc:Pre-Depends}
Dépend : ${python:Depends}, ${misc:Depends}.
Description : Un paquet d'exemple pour démontrer l'empaquetage de virtualenv Debian avec dh-virtualenv
     .
     Il s'agit d'une distribution de "sampleproject" en tant que projet autonome.
     Python virtualenv emballé dans un paquet Debian (paquet " omnibus "),
     tous les passagers à bord). Le virtualenv empaqueté est maintenu en synchronisation avec
     l'interprète de l'hôte automatiquement.
     .
     Voir
https://github.com/spotify/dh-virtualenv pour plus de détails.

Vous voudrez également modifier la description longue.

cookiecutter.json

Comprend vos paramètres initiaux. Non requis pour l'emballage.

copyright

Votre fichier de copyright, avec votre licence (par exemple MIT). Il est pré-rempli avec votre nom, l'année, l'adresse électronique et "certains droits réservés".

règles

C'est un Makefile, pour construire réellement votre paquet. Il est pré-rempli par le modèle cookiecutter.

exemple de projet.liens

Ce fichier vous permet de créer des liens lors de l'installation . Le nom du fichier comprendra le nom de votre projet au lieu de exemple de projet.

Réf : https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink

projet type.postinst

Ce fichier vous permet d'exécuter des étapes de configuration supplémentaires après l'installation (par exemple, l'activation de votre script python en tant que service). Le nom du fichier comprendra le nom de votre projet au lieu de exemple de projet.

exemple de projet.triggers

D'après ce que j'ai compris, c'est pour que dh-virtualenv installe un interpréteur python plus récent dans l'environnement virtuel à expédier, si celui du système (votre boîte de développement) est mis à jour. Le nom du fichier comprendra le nom de votre projet au lieu de exemple de projet.

Cela peut être ou non le cas, je ne l'ai pas testé.

setup.py

Comme mentionné ci-dessus, nous avons besoin d'un setup.py fichier. C'est la manière standard dont les applications sont empaquetées sous Python (elles sont livrées avec un setup.py, qui est exécuté pour diverses tâches liées à l'empaquetage).

Un setup.py simple peut être vu sur cette page :

https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py

Toutes les entrées de ces fichiers ne sont pas nécessaires. Par exemple, vous pouvez laisser de côté les classificateurs. J'ai le setup.py suivant :

image

Remarque : le numéro de version et les autres informations contenues ici concernent votre paquet Python (qui sera créé au cours de la construction d'un paquet Debian avec votre virtualenv).

Structure pour votre code

Votre code se trouve maintenant dans un sous-répertoire du répertoire principal de sampleproject :

image

Dans ce cas, le sous-répertoire porte le même nom que le répertoire principal.

Notez que le fichier __init__.py

Le fichier sample.py est celui que nous avons utilisé plus haut, mais un peu retravaillé pour ressembler à ceci :

image

En outre, j'ai mis en place un environnement virtuel pour les tests tout en développant à l'intérieur du répertoire principal (de premier niveau) du projet pilote :

virtualenv -p /usr/bin/python3 sp_env

appelé sp_env pour l'environnement de l'échantillon de projet

Entrer dans l'environnement :

source sp_env/bin/activate

Installez la bibliothèque randstr dans cet environnement :

pip3 install randstr

et maintenant nous pouvons exécuter le code :

python3 sampleproject/sample.py

image

OK. Quitter l'environnement ( ! important !)et essayez à nouveau de construire le paquet :

désactiver

dpkg-buildpackage -us -uc

Par défaut (à cause de l'emporte-pièce), votre paquet sera créé pour être installé dans /opt/venvs/ :

Nouvel exécutable python dans /home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3

Cela peut être modifié dans le debian/rules fichier.

Maintenant, le paquet a été construit, et déposé en dehors du répertoire supérieur de sampleproject (à l'intérieur du répertoire tutorial) :

image

Vous pouvez installer le fichier .deb en utilisant dpkg :

sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb

Voir les résultats de l'installation avec

arbre /opt/venvs

127 répertoires et 945 fichiers ont été installés.

Maintenant vous pouvez essayer d'exécuter le projet d'exemple en utilisant

/opt/venvs/sampleproject/bin/sampleproject

exigences / dépendances

L'application ne s'exécute pas comme (peut-être) prévu, mais lance une erreur sur la non présence de randstr. Que se passe-t-il ?

image

La raison en est que dh-virtualenv ne connaît pas l'exigence que nous avons, de regrouper le paquet randstr pendant le processus de construction. C'est la dernière pièce du puzzle.

Les exigences doivent être ajoutées à la setup.pycomme un moyen d'indiquer à pip les paquets supplémentaires qui doivent être installés dans l'environnement virtuel en cours de création.

ajoutez ce qui suit à setup.py :

install_requires=[

        randstr

]

Le fichier entier ressemblera alors à ceci :

image

Dans mes tests, le fichier requirements.txt placé en haut de l'écran a donné les résultats suivants pas influencer le comportement de dh-virtualenv et des paquets Python réellement inclus dans le paquet Debian. Si vous le souhaitez toujours, voici comment :

pip vous offre un moyen de sortir les dépendances exactes que vous avez utilisées pour le développement dans l'environnement virtuel. Entrez dans l'environnement virtuel :

source sp_env/bin/activate

Et créez le fichier requirements.txt :

pip3 freeze > requirements.txt

Maintenant vous pouvez jeter un coup d'oeil à ce fichier :

cat requirements.txt

image

Même si ce fichier ne semble pas être utilisé par dh-virtualenv (peut-être doit-il être placé dans un autre sous-répertoire), c'est une bonne référence pour vous-même, pour voir quels paquets vous devez mettre comme dépendances dans la partie install_requires de setup.py.

Notez que le fichier sampleproject.links nous a offert un moyen pratique de lier ceci dans le dossier /usr/bin, je vais donc enlever le signe de commentaire pour la prochaine construction :

image

Ceci étant fait, il est temps de purger le sampleproject, de le recompiler, puis de l'installer. N'oubliez pas de désactiver d'abord !

désactiver

sudo apt purge sampleproject

dpkg-buildpackage -us -uc

cd...

sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb

Cette fois, le paquet devrait être accessible en utilisant sampleproject :

quel projet type

exemple de projet

image

Réf : https://packaging.python.org/discussions/install-requires-vs-requirements/

Conseil bonus : changer le lieu d'installation

/opt/venvs n'est pas un " endroit " très Debian pour mettre un paquet.

Les spécifications sont ici :

http://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html

https://unix.stackexchange.com/questions/10127/why-did-my-package-get-installed-to-opt

  • /usr/local est pas pour les paquets
  • /opt n'est pas destiné aux paquets Debian proprement dits (c'est pour les logiciels tiers installés par l'utilisateur).

http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html

Les applications peuvent utiliser un seul sous-répertoire sous le nom de /usr/lib. Si une application utilise un sous-répertoire, toutes les données dépendantes de l'architecture utilisées exclusivement par l'application doivent être placées dans ce sous-répertoire.

https://wiki.debian.org/HowToPackageForDebian

https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy

"L'exigence du FHS selon laquelle les fichiers statiques spécifiques à l'application et indépendants de l'architecture doivent se trouver dans /usr/share est relaxé en une suggestion. En particulier, un sous-répertoire de /usr/lib peut être utilisé par un paquet (ou une collection de paquets) pour contenir un mélange de fichiers indépendants de l'architecture et de fichiers dépendants de l'architecture. Cependant, lorsqu'un répertoire est entièrement composé de fichiers indépendants de l'architecture, il doit être situé dans le répertoire /usr/share."

Le meilleur emplacement me semble être /usr/share

Nous devons modifier deux fichiers :

dans debian/rules DH_VIRTUALENV_INSTALL_ROOT doit être changé en /usr/share, comme ceci :

image

et debian/sampleproject.links doivent être modifiés :

image

Aussi, nous ferons une nouvelle entrée dans le changelog :

dch -i

image

modifier simplement le texte, pour refléter un nouveau numéro de version, et une entrée pour le changelog.

Ensuite, le projet peut être reconstruit :

dpkg-buildpackage -us -uc

Après l'installation, vous pouvez vérifier qu'effectivement le nouvel emplacement est utilisé :

image

Le paquet occupera environ 16 Mo sur votre système cible, grâce à l'environnement virtuel et à tout ce qui est livré avec. Cela pourrait probablement être réduit par certains paramètres, mais cet exercice est laissé au lecteur.

Amusez-vous bien à emballer !