Ich bin generell eher kein Python-Entwickler und kam irgendwann in die Situation, Python-Abhängigkeiten bei der Nutzung von AWS und unterschiedlichen CLI-Tools (aws-cli, eb-cli, etc.) zu verwalten. Jetzt kann man natürlich sagen: „Egal – installiert euch lokal-global das aktuellste aws/eb-cli und gut ist“.
Mir war es aber im Sinne der Professionalität wichtig, das auch projektbezogen und für eine Kollaboration reproduzierbar zu machen. Folgende Problemstellungen ergaben sich letztlich daraus:
- Ich brauche Python möglicherweise in verschiedenen Versionen – gibt es sowas wie „nvm“ auch für Python?
- Wie kann ich mit pip(3) installierte Abhängigkeiten reproduzierbar verwalten?
Lösungsansätze
Für beide Problemstellungen existiert jeweils eine praktische Lösung, die ich an dieser Stelle kurz vorstellen möchte.
Verschiedene Python-Versionen
Die Lösung des Problems heißt „virtualenv“. Das CLI-Tool bietet die Möglichkeit, isolierte Python-Umgebungen z. B. je Projekt mit gewünschter Python-Version zu erstellen. Die Installation läuft normalerweise über pip(3), viele Betriebssysteme bieten allerdings auch eigene Pakete für virtualenv an.
In meinem Fall (macOS), habe ich Python 3 via Homebrew installiert und als Standard-Python-Version für mein System gelinkt. Dort habe ich dann virtualenv via pip3 installiert. Das würde folgendermaßen funktionieren:
brew install python && brew unlink python && brew link python && pip3 install virtualenv
Um eine neue Python-Umgebung anzulegen, wird folgendes Kommando benutzt:
virtualenv .python_env
Die Angabe hinter dem Befehl steht für für den Namen des Ordners, in dem die neue Umgebung ihre Daten hält. Mit Hilfe des Parameters „-p“ kann die gewünschte Python-Binary – wenn sie im PATH liegt einfach so, andernfalls unter Angabe des kompletten Pfades – angegeben werden, um so eine Umgebung mit der benötigten Version zu erhalten. Standardmäßig wird die Python-Version genutzt, unter der virtualenv installiert ist.
Aktivieren der Umgebung
Anschließend muss die neue Umgebung aktiviert werden, womit natürlich auch möglicherweise global installierte Pakete „verloren“ gehen, d. h. dass sie nicht verfügbar sind:
source .python_env/bin/activate
Falls euch /.python_env/ als Ordner nicht zugesagt hat, müsste der Name natürlich entsprechend angepasst werden.
Wenn ihr mit der Arbeit an eurem Projekt fertig seid, könnt Ihr entweder das Terminal schließen bzw. einen neuen Tab nutzen oder mit dem Befehl deactivate, der nur innerhalb der virtualenv-Umgebung verfügbar ist, die Python-Umgebung verlassen.
Somit wäre das erste Problem gelöst. Kommen wir nun zum zweiten Teil:
Abhängigkeiten projektbezogen verwalten
Der Paketmanager pip(3) bringt hierfür die benötigte Funktion bereits mit: „freeze“. Dieses Kommando gibt die aktuell installierten Python-Pakete inklusive Version in einem lesbaren aber auch für pip verständlichen Format aus.
Allerdings sollte man eine Sache beachten: Bei der Nutzung von virtualenv unterscheidet sich die Ausgabe je nach aktiver Umgebung! Ist keine Umgebung aktiv, gibt pip die für die standardmäßig aktiven Python-Version installierten Pakete aus (Abb. 1 & Abb. 2).
Wie man sehen kann, sind das ganz schön viele Abhängigkeiten. Das liegt daran, das pip(3) in diesem Fall nicht nur die eigentlichen Abhängigkeiten auflistet, sondern auch die Abhängigkeiten derer, und so weiter …
Abhängigkeiten eingrenzen
Man hat nun zwei Möglichkeiten:
1. Nutzen von pip freeze > python_requirements.txt
, um eine Art „Lock-Datei“ mit den Abhängigkeiten zu erstellen
2. Liste der Abhängigkeiten via pip freeze
ausgeben lassen, diese dann manuell prüfen und entsprechend selbst eine Datei mit relevanten Abhängigkeiten erstellen
Wenn nun eine entsprechende Datei mit Abhängigkeiten existiert, können sie über den folgenden Befehl automatisch installiert werden:
pip install -r python_requirements.txt
Der Wert der Parameters „-r“ steht natürlich für die Datei, die entsprechend die Liste der Abhängigkeiten mit Version enthält.
Zusammenfassung
Um es mir selbst etwas leichter zu machen, habe ich mir inzwischen einen One-Liner gebastelt, den man sich gerne auch als Alias eintragen kann; Voraussetzung in meinem Fall wäre, das die Projekt-Struktur – /.python_env/ und python_requirements.txt – immer gleich sein müssen.
virtualenv .python_env && source .python_env/bin/activate && pip install -r python_requirements.txt
Schreibe einen Kommentar