Paketierung von Python-Projekten für Debian / Raspbian mit dh-virtualenv
Dieser Artikel soll Entwicklern, die Python nicht oft verwenden, einige Dinge erklären, da sie sonst mit einigen Konzepten Schwierigkeiten haben könnten.
Als Einführung in die hier besprochenen Konzepte empfehle ich den Vortrag des folgenden Artikels:
pypi.org
pypi.org ist ein offizielles Repository mit Software für die Programmiersprache Python. Es enthält Bibliotheken, die wir in unseren Projekten verwenden möchten und die nicht standardmäßig mit Python ausgeliefert werden.
Das Problem
Unser Ziel ist es, eine in Python geschriebene Anwendung (mit dem Ziel Python3) als .deb-Paket für Raspbian zu verpacken (was im Großen und Ganzen mit Debian vergleichbar ist).
Unsere Anwendung ist von mehreren Python-Bibliotheken abhängig.
Wir möchten zum Beispiel die Anfragen Bibliothek. Die Anforderungsbibliothek selbst hängt von anderen Bibliotheken ab, z.B. chardet, urllib3, etc.
Die manuelle Verwaltung dieser Abhängigkeiten und der manuelle Versand des erforderlichen Bibliothekscodes ist naturgemäß unpraktisch.
pip
Python hat sein eigenes Paket-/Abhängigkeitsverwaltungssystem, genannt pip
pip ermöglicht es Ihnen, Python-Bibliotheken und -Anwendungen zu installieren, so dass Ihr eigener Code diese Bibliotheken nutzen kann.
Hier gibt es zwei Probleme:
- wir wollen das Paket als eine Debian-Paketfür die Endbenutzer leicht zu installieren. Wir können mit Sicherheit davon ausgehen, dass auf einer beträchtlichen Anzahl von Zielsystemen die entsprechenden Python-Bibliotheken vom Benutzer nicht installiert wurden
- wenn wir versuchen, diese Bibliotheken zu installieren systemweit im Namen des BenutzersEs kann sein, dass die Kompatibilität mit einigen anderen Paketen nicht mehr gegeben ist (z. B. aufgrund von API-Änderungen zwischen den Versionen der Bibliotheken).
Deshalb brauchen wir eine Lösung.
virtualenv
virtualenv ermöglicht es uns, virtuelle Umgebungen für Python zu erstellen.
In diesen virtuellen Umgebungen haben wir:
- unser eigener Python-Interpreter
- Kopien der erforderlichen Standardbibliotheken
- unser eigener Pip
- unsere eigene "systemweite" Bibliothek
Praktischer Teil: Ausprobieren von virtualenv
Installieren Sie virtualenv (als Teil von dh-virtualenv, zu dem wir gleich noch kommen werden), indem Sie dies tun:
sudo apt install dh-virtualenv
Da requests auf meiner Testbox bereits systemweit installiert ist, werden wir ein anderes Paket als Beispiel verwenden. randstr ermöglicht es Ihnen, eine zufällige Zeichenfolge zu erzeugen.
Prüfen Sie, ob randstr ist systemweit installiert:
pip3 randstr anzeigen
Dies sollte nichts ergeben. Gibt an, dass dieses Paket nicht systemweit installiert ist:
Jetzt werden wir eine virtuelle Umgebung erstellen. Der Ordner für die virtuelle Umgebung muss sich NICHT in Ihrem Code-Ordner befinden, aber er kann. Sie sollten ihn in GIT ignorieren.
Nehmen wir an, wir haben ein Verzeichnis /home/pi/tutorial
Wechseln Sie in dieses Verzeichnis, und erstellen Sie einen neuen Umgebungsordner env:
cd /home/pi/tutorial
welches python3
virtualenv -p /usr/bin/python3 env
Hinweis: Sie sollten den Python-Interpreter angeben, wenn Sie Python 3 wünschen, da sonst Python 2 verwendet wird. Ich verwende Python 3. (Virtualenv wird mit dem Interpreter /usr/bin/python2 ausgeführt)
python3 verrät Ihnen, wo sich die Python3-Binärdatei befindet, passen Sie den Pfad für virtualenv entsprechend an.
die Umwelt zu aktivieren:
Quelle env/bin/activate
(Dieser Befehlspfad setzt voraus, dass Sie sich im Verzeichnis des Tutorials befinden). Bitte beachten Sie auch, dass es sich nicht um ein ausführbares Skript handelt - Sie müssen Quelle um es mit Ihrem Bash-Terminal zu verwenden.
Beachten Sie, dass (env) der Eingabeaufforderung vorangestellt ist:
Dies bedeutet, dass die Umgebung aktiv ist. Jetzt können Sie pip3 erneut ausführen, aber dieses Mal wird pip3 seine Arbeit in der virtuellen Umgebung ausführen:
pip3 randstr anzeigen
pip3 Anfragen anzeigen
sollte immer noch nichts ergeben. Die zweite Zeile zeigt ebenfalls nichts an - was zeigt, dass wir uns (wenn requests systemweit installiert ist) tatsächlich in einer virtuellen Umgebung befinden.
Installieren Sie nun randstr:
pip3 install randstr
und prüfen Sie erneut, ob sie installiert ist:
pip3 randstr anzeigen
Dieses Mal zeigt es an, dass randstr installiert ist. Es wurde in env/lib/python3.5/site-packages installiert:
Während die Umgebung noch aktiviert ist, wollen wir eine kleine Python-Beispielanwendung schreiben:
nano beispiel.py
fügen Sie den folgenden Code ein, der eine zufällige Zeichenkette unter Verwendung der neuen Bibliothek erzeugt, die wir gerade installiert haben:
from randstr import randstr
print("Hallo Welt")
print(randstr())
und speichern.
Führen Sie den Code mit python3 aus:
python3 beispiel.py
solange die Umgebung noch aktiv ist, wird dies funktionieren:
Jetzt ist es an der Zeit, die Umgebung zu verlassen, um zu sehen, ob der Code noch läuft:
deaktivieren
Ihre Eingabeaufforderung wird sich wieder normalisieren. Und
python3 beispiel.py
wird eine Fehlermeldung ausgeben, dass kein Modul 'randstr' auf Ihrem System existiert. Das ist genau das Verhalten, das wir wollen!
Sie können einen Blick auf den env-Ordner werfen und sehen, dass er alle notwendigen Dinge enthält, um Ihren Python-Code auszuführen, einschließlich Bibliotheken, die ausführbare Python-Datei, pip und mehr.
Debian Virtualenv-Paketierung mit dh-virtualenv
OK, jetzt, wo die Grundlagen geklärt sind, wollen wir eine virtualenv zusammen mit unserem Code paketieren, so dass unsere Anwendung zuverlässig und ohne Störung anderer Anwendungen auf den Computern unserer Benutzer läuft.
Dies ist der Ort, an dem dh-virtualenv ins Bild. dh-virtualenv ist ein Zusatz zu den Debian-Bauskripten, der es Ihnen erlaubt, virtuelle Umgebungen zu paketieren.
Wir müssen eine grundlegende Paketstruktur für unser neues Paket erstellen. Dies ist der Punkt Keksausstecher wird helfen.
Keksausstecher
cookiecutter erstellt für Sie neue Projekte auf der Grundlage von Vorlagen und reduziert so den Aufwand und die Zeit, die Sie für die Entwicklung und den Umgang mit den vielen erforderlichen Dateien benötigen.
https://cookiecutter.readthedocs.io/en/latest/
sudo apt install cookiecutter
Hinweis: Das Paket python3-cookiecutter stellt ein Python-Modul für Python 3 bereit. Was wir wollen, ist die Anwendung selbst, die mit dem Paket cookiecutter installiert wird (siehe oben). Dies könnte Python 2 einbeziehen, aber - na ja.
cookiecutter ist für Ihre Endbenutzer nicht notwendig, er wird nur verwendet, um mehrere Dateien für Ihr Paket zu erstellen.
Erstellen Sie ein Verzeichnis für ein Beispielprojekt, auf das wir die Vorlage anwenden werden (ich befinde mich immer noch im Verzeichnis des Tutorials):
mkdir sampleproject
cd sampleproject
Mit einer speziellen Form für dh-virtualenv können wir viele der notwendigen Dateien einrichten:
https://github.com/Springerle/dh-virtualenv-mold
Keksausstecher https://github.com/Springerle/dh-virtualenv-mold.git
Dabei werden Ihnen mehrere Fragen gestellt.
Beachten Sie, dass der Ordner debian heißen sollte, auch wenn Sie für Raspbian paketieren - behalten Sie daher den Namen debian bei.
Dadurch werden die folgenden Dateien installiert:
Nun müssen Sie die folgenden Befehle ausführen, wie in den Anweisungen unter dh-virtualenv-mold beschrieben:
sudo apt-get install build-essential debhelper devscripts equivssudo mk-build-deps --install debian/control
Um das Paket später zu erstellen, führen Sie den folgenden Befehl vom obersten Verzeichnis Ihres Projekts aus:
dpkg-buildpackage -uc -us -b
Im Moment wird der Befehl jedoch fehlschlagen, weil setup.py fehlt. Wir werden in Kürze zu setup.py und requirements.txt kommen:
/usr/bin/python3: Die Datei 'setup.py' kann nicht geöffnet werden: [Errno 2] Keine solche Datei oder Verzeichnis
Informationen zu den einzelnen Dateien
Änderungsprotokoll
Diese Datei enthält Ihre Release- und Versionsinformationen für das Paket. Sie können sie mit einem speziellen Werkzeug aktualisieren, dch.
Diese Datei ist kein Changelog für Ihre Anwendung, sondern nur ein Changelog für die Verpackung Ihrer Anwendung.
kompat
Diese Datei enthält eine spezielle magische Zahl "9". (aus Kompatibilitätsgründen ist es in Ordnung, sie so zu belassen)
Kontrolle
Dies ist die wichtigste Datei, um Paketeinstellungen und Abhängigkeiten auf Debian-Ebene festzulegen. Wenn Ihre Anwendung zum Beispiel davon abhängt, dass der omxplayer installiert ist, muss er hier als Abhängigkeit eingetragen werden:
Quelle: sampleproject
Abschnitt: contrib/python
Priorität: extra
Maintainer: Maximilian Batz
Build-Abhängigkeiten: debhelper (>= 9), python, python-dev, dh-virtualenv (>= 0.10), tar
Normen-Version: 3.9.5
Homepage: https://picockpit.com
Paket: sampleproject
Architektur: beliebig
Vorausgesetzt wird: dpkg (>= 1.16.1), python2.7 | python3, ${misc:Pre-Depends}
Abhängig von: ${python:Depends}, ${misc:Depends}
Beschreibung: Ein Beispielpaket zur Demonstration der Virtualenv-Debian-Paketierung mit dh-virtualenv
.
Dies ist eine Verteilung von "sampleproject" als eigenständiges
Python virtualenv verpackt in ein Debian-Paket ("omnibus"-Paket,
alle Passagiere an Bord). Die verpackte virtualenv wird synchron gehalten mit
den Interpreter des Hosts automatisch.
.
Siehe https://github.com/spotify/dh-virtualenv für weitere Einzelheiten.
Sie werden auch die lange Beschreibung bearbeiten wollen.
cookiecutter.json
Beinhaltet Ihre Grundeinstellungen. Für die Verpackung nicht erforderlich.
Copyright
Ihre Copyright-Datei mit Ihrer Lizenz (z. B. MIT). Sie ist bereits mit Ihrem Namen, Jahr, E-Mail und "Einige Rechte vorbehalten" ausgefüllt.
Regeln
Dies ist ein Makefile, um Ihr Paket tatsächlich zu bauen. Es wird von der Cookiecutter-Vorlage vorausgefüllt.
beispielprojekt.links
Mit dieser Datei können Sie während der Installation Verknüpfungen erstellen. Der Dateiname enthält Ihren Projektnamen anstelle von Beispielprojekt.
Ref: https://stackoverflow.com/questions/9965717/debian-rules-file-make-a-symlink
musterprojekt.postinst
Mit dieser Datei können Sie nach der Installation zusätzliche Installationsschritte ausführen (z. B. Ihr Python-Skript als Dienst aktivieren). Der Dateiname enthält Ihren Projektnamen anstelle von Beispielprojekt.
beispielprojekt.auslöser
Soweit ich es verstehe, ist dies für dh-virtualenv, um einen neueren Python-Interpreter in die virtuelle Umgebung zu installieren, wenn das System (Ihre Entwicklungsbox) aktualisiert wird. Der Dateiname enthält Ihren Projektnamen anstelle von Beispielprojekt.
Dies kann der Fall sein oder auch nicht, ich habe es nicht getestet.
setup.py
Wie bereits erwähnt, benötigen wir eine setup.py Datei. Dies ist die Standardmethode, wie Anwendungen unter Python verpackt werden (sie werden mit einer setup.py ausgeliefert, die für verschiedene Aufgaben im Zusammenhang mit der Paketierung ausgeführt wird).
Eine einfache setup.py ist auf dieser Seite zu sehen:
https://github.com/benjaminirving/python-debian-packaging-example/blob/master/setup.py
Nicht alle Einträge in diesen Dateien sind notwendig. Sie können zum Beispiel die Klassifikatoren weglassen. Ich habe die folgende setup.py:
Hinweis: Die Versionsnummer und andere Informationen hier drin sind für Ihr Python-Paket (das im Laufe der Erstellung eines Debian-Pakets mit Ihrer Virtualenv erstellt wird).
Struktur für Ihren Code
Ihr Code befindet sich nun in einem Unterverzeichnis des Hauptverzeichnisses des Beispielprojekts:
Das Unterverzeichnis hat in diesem Fall den gleichen Namen wie das Hauptverzeichnis.
Beachten Sie die __init__.py
Die sample.py ist diejenige, die wir oben verwendet haben, aber ein wenig überarbeitet, so dass sie wie folgt aussieht:
Zusätzlich habe ich eine virtuelle Umgebung zum Testen während der Entwicklung im Hauptverzeichnis (oberste Ebene) des Beispielprojekts eingerichtet:
virtualenv -p /usr/bin/python3 sp_env
sp_env für Beispielprojektumgebung genannt
Eintritt in die Umwelt:
Quelle sp_env/bin/activate
Installieren Sie die randstr-Bibliothek in diese Umgebung:
pip3 install randstr
und jetzt können wir den Code ausführen:
python3 beispielprojekt/beispiel.py
OK. Verlassen Sie die Umgebung (! wichtig!)und versuchen Sie erneut, das Paket zu erstellen:
deaktivieren
dpkg-buildpackage -us -uc
Standardmäßig (wegen der Ausstechform) wird Ihr Paket zur Installation in /opt/venvs/ erstellt:
Neue ausführbare Python-Datei in /home/pi/tutorial/sampleproject/debian/sampleproject/opt/venvs/sampleproject/bin/python3
Dies kann in der Datei debian/regeln Datei.
Das Paket wurde nun erstellt und außerhalb des Hauptverzeichnisses von sampleproject (innerhalb des Verzeichnisses tutorial) abgelegt:
Sie können die .deb-Datei mit dpkg installieren:
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Sehen Sie sich die Installationsergebnisse mit
Baum /opt/venvs
127 Verzeichnisse und 945 Dateien wurden installiert.
Jetzt können Sie versuchen, das Beispielprojekt auszuführen, indem Sie
/opt/venvs/sampleproject/bin/sampleproject
Anforderungen/Abhängigkeiten
Die Anwendung läuft nicht wie (vielleicht) erwartet, sondern gibt eine Fehlermeldung aus, dass randstr nicht vorhanden ist. Woran liegt das?
Der Grund dafür ist, dass dh-virtualenv die Anforderung nicht kennt, das Paket randstr während des Build-Prozesses zu bündeln. Dies ist das letzte Teil des Puzzles.
Die Anforderungen müssen in die setup.pyals eine Möglichkeit, pip mitzuteilen, welche zusätzlichen Pakete in der zu erstellenden virtuellen Umgebung installiert werden müssen.
fügen Sie Folgendes in die Datei setup.py ein:
install_requires=[
randstr'
]
Die gesamte Datei sieht dann wie folgt aus:
In meinen Tests hat die auf der obersten Ebene platzierte requirements.txt nicht das Verhalten von dh-virtualenv und den Python-Paketen, die im Debian-Paket enthalten sind, beeinflussen. Wenn Sie es trotzdem wollen, hier ist die Anleitung:
pip bietet Ihnen eine Möglichkeit, genau die Abhängigkeiten, die Sie für die Entwicklung verwendet haben, in die virtuelle Umgebung zu übertragen. Geben Sie die virtuelle Umgebung ein:
Quelle sp_env/bin/activate
Und erstellen Sie die Datei requirements.txt:
pip3 freeze > requirements.txt
Jetzt können Sie sich diese Datei ansehen:
cat Anforderungen.txt
Auch wenn diese Datei nicht von dh-virtualenv verwendet zu werden scheint (vielleicht muss sie in ein anderes Unterverzeichnis), ist sie eine gute Referenz für Sie selbst, um zu sehen, welche Pakete Sie als Abhängigkeiten in den install_requires-Teil von setup.py eintragen sollten.
Beachten Sie, dass die Datei sampleproject.links uns eine bequeme Möglichkeit bot, diese in den Ordner /usr/bin zu verlinken, ich werde daher das Kommentarzeichen für den nächsten Build entfernen:
Nun ist es an der Zeit, das Beispielprojekt zu löschen, es neu zu erstellen und zu installieren. Vergessen Sie nicht, es vorher zu deaktivieren!
deaktivieren
sudo apt purge sampleproject
dpkg-buildpackage -us -uc
cd ..
sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb
Dieses Mal sollte das Paket über sampleproject zugänglich sein:
welches Musterprojekt
Beispielprojekt
Ref: https://packaging.python.org/discussions/install-requires-vs-requirements/
Bonus-Tipp: Änderung des Installationsortes
/opt/venvs ist nicht gerade ein Debian-"Ort", um ein Paket abzulegen.
Die Spezifikationen finden Sie hier:
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 ist nicht für Pakete
- /opt ist nicht für Debian-Pakete selbst (es ist für vom Benutzer installierte Software von Drittanbietern)
http://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch04s06.html
Anwendungen können ein einzelnes Unterverzeichnis unter /usr/lib
. Wenn eine Anwendung ein Unterverzeichnis verwendet, müssen alle architekturabhängigen Daten, die ausschließlich von der Anwendung verwendet werden, in diesem Unterverzeichnis abgelegt werden.
https://wiki.debian.org/HowToPackageForDebian
https://www.debian.org/doc/debian-policy/ch-opersys.html#file-system-hierarchy
"Die FHS-Anforderung, dass sich architekturunabhängige anwendungsspezifische statische Dateien in /usr/share
zu einer Anregung gelockert wird. Im Besonderen, ein Unterverzeichnis von /usr/lib
kann von einem Paket verwendet werden (oder eine Sammlung von Paketen), die eine Mischung aus architekturunabhängigen und architekturabhängigen Dateien enthalten. Wenn ein Verzeichnis jedoch vollständig aus architekturunabhängigen Dateien besteht, sollte es sich in /usr/share
."
Der beste Speicherort scheint mir /usr/share zu sein
Wir müssen zwei Dateien bearbeiten:
in debian/rules muss DH_VIRTUALENV_INSTALL_ROOT auf /usr/share geändert werden, etwa so:
und debian/sampleproject.links müssen geändert werden:
Außerdem werden wir einen neuen Eintrag im Changelog vornehmen:
dch -i
bearbeiten Sie einfach den Text, um eine neue Versionsnummer und einen Eintrag für das Änderungsprotokoll anzugeben.
Dann kann das Projekt neu erstellt werden:
dpkg-buildpackage -us -uc
Nach der Installation können Sie überprüfen, ob der neue Speicherort tatsächlich verwendet wird:
Das Paket benötigt auf Ihrem Zielsystem etwa 16 MB, dank der virtuellen Umgebung und allem, was mitgeliefert wird. Dies könnte wahrscheinlich durch einige Parameter reduziert werden, aber diese Aufgabe bleibt dem Leser überlassen.
Viel Spaß beim Verpacken!