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:

Bild

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.

Bild

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:

Bild

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

Bild

Dieses Mal zeigt es an, dass randstr installiert ist. Es wurde in env/lib/python3.5/site-packages installiert:

Bild

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:

Bild

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!

Bild

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.

Bild

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:

Bild

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 equivs
sudo 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:

Bild

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:

Bild

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:

Bild

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

Bild

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:

Bild

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?

Bild

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:

Bild

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

Bild

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:

Bild

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

Bild

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:

Bild

und debian/sampleproject.links müssen geändert werden:

Bild

Außerdem werden wir einen neuen Eintrag im Changelog vornehmen:

dch -i

Bild

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:

Bild

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!