Pipenv: Eine Anleitung zum neuen Python Packaging Tool
Pipenv ist ein Paketierungswerkzeug für Python, das einige häufig auftretende Probleme im Zusammenhang mit dem typischen Workflow mitpip
,virtualenv
und den guten altenrequirements.txt
löst.
Zusätzlich zur Behebung einiger häufig auftretender Probleme wird der Entwicklungsprozess in einem einzigen Befehlszeilentool konsolidiert und vereinfacht.
In diesem Handbuch wird erläutert, welche Probleme Pipenv löst und wie Sie Ihre Python-Abhängigkeiten mit Pipenv verwalten. Darüber hinaus wird erläutert, wie Pipenv zu früheren Methoden für die Verteilung vonpackagepasst.
Free Bonus:Click here to get access to a free 5-day class zeigt Ihnen, wie Sie häufige Probleme mit dem Abhängigkeitsmanagement mit Tools wie Pip, PyPI, Virtualenv und Anforderungsdateien vermeiden können.
Probleme, die Pipenv löst
Um die Vorteile von Pipenv zu verstehen, ist es wichtig, die aktuellen Methoden für das Packen und das Abhängigkeitsmanagement in Python durchzugehen.
Beginnen wir mit einer typischen Situation beim Umgang mit Paketen von Drittanbietern. Wir werden uns dann auf den Weg zur Bereitstellung einer vollständigen Python-Anwendung machen.
Abhängigkeitsmanagement mitrequirements.txt
Stellen Sie sich vor, Sie arbeiten an einem Python-Projekt, das ein Drittanbieterpaket wieflask
verwendet. Sie müssen diese Anforderung angeben, damit andere Entwickler und automatisierte Systeme Ihre Anwendung ausführen können.
Sie beschließen also, die Abhängigkeit vonflask
in eine Datei vonrequirements.txt
aufzunehmen:
flask
Großartig, alles funktioniert lokal einwandfrei, und nachdem Sie Ihre App eine Weile gehackt haben, entscheiden Sie sich, sie in die Produktion zu verschieben. Hier wird es ein bisschen unheimlich ...
Die obigerequirements.txt
-Datei gibt nicht an, welche Version vonflask
verwendet werden soll. In diesem Fall installiertpip install -r requirements.txt
standardmäßig die neueste Version. Dies ist in Ordnung, es sei denn, in der neuesten Version gibt es Änderungen an der Benutzeroberfläche oder am Verhalten, die unsere Anwendung beschädigen.
Nehmen wir für dieses Beispiel an, dass eine neue Version vonflask
veröffentlicht wurde. Es ist jedoch nicht abwärtskompatibel mit der Version, die Sie während der Entwicklung verwendet haben.
Angenommen, Sie stellen Ihre Anwendung für die Produktion bereit und führen einpip install -r requirements.txt
aus. Pip erhält die neueste, nicht abwärtskompatible Version vonflask
, und einfach so bricht Ihre Anwendung… in der Produktion.
“But hey, it worked on my machine!” - Ich war selbst dort und es ist kein großartiges Gefühl.
Zu diesem Zeitpunkt wissen Sie, dass die Version vonflask
, die Sie während der Entwicklung verwendet haben, einwandfrei funktioniert hat. Um Abhilfe zu schaffen, versuchen Sie, inrequirements.txt
etwas spezifischer zu sein. Sie fügen der Abhängigkeit vonflask
version specifier hinzu. Dies wird auch alspinning-Abhängigkeit bezeichnet:
flask==0.12.1
Durch das Anheften der Abhängigkeit vonflask
an eine bestimmte Version wird sichergestellt, dasspip install -r requirements.txt
die genaue Version vonflask
festlegt, die Sie während der Entwicklung verwendet haben. Aber wirklich?
Beachten Sie, dassflask
selbst ebenfalls Abhängigkeiten aufweist (diepip
automatisch installiert). flask
elbst gibt jedoch keine genauen Versionen für seine Abhängigkeiten an. Zum Beispiel erlaubt es jede Version vonWerkzeug>=0.14
.
Nehmen wir für dieses Beispiel erneut an, dass eine neue Version vonWerkzeug
veröffentlicht wurde, die jedoch einen Show-Stopper-Fehler in Ihre Anwendung einführt.
Wenn Sie diesmalpip install -r requirements.txt
in der Produktion ausführen, erhalten Sieflask==0.12.1
, da Sie diese Anforderung festgelegt haben. Leider erhalten Sie die neueste fehlerhafte Version vonWerkzeug
. Auch hier bricht das Produkt in der Produktion.
Das eigentliche Problem hierbei ist, dassthe build isn’t deterministic. Damit meine ich, dass pip bei gleicher Eingabe (derrequirements.txt
-Datei) nicht immer dieselbe Umgebung erzeugt. Derzeit können Sie die genaue Umgebung, die Sie auf Ihrer Entwicklungsmaschine in der Produktion haben, nicht einfach replizieren.
Die typische Lösung für dieses Problem ist die Verwendung vonpip freeze
. Mit diesem Befehl können Sie genaue Versionen für alle derzeit installierten Bibliotheken von Drittanbietern abrufen, einschließlich der automatisch installierten Unterabhängigkeiten pip. So können Sie alles in der Entwicklung einfrieren, um sicherzustellen, dass Sie dieselbe Produktionsumgebung haben.
Das Ausführen vonpip freeze
führt zu fixierten Abhängigkeiten, die Sie zurequirements.txt
hinzufügen können:
click==6.7
Flask==0.12.1
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1
Mit diesen angehefteten Abhängigkeiten können Sie sicherstellen, dass die in Ihrer Produktionsumgebung installierten Pakete genau mit denen in Ihrer Entwicklungsumgebung übereinstimmen, damit Ihr Produkt nicht unerwartet kaputt geht. Diese „Lösung“ führt leider zu einer ganzen Reihe neuer Probleme.
Nachdem Sie die genauen Versionen aller Pakete von Drittanbietern angegeben haben, sind Sie dafür verantwortlich, diese Versionen auf dem neuesten Stand zu halten, auch wenn es sich um Unterabhängigkeiten vonflask
handelt. Was ist, wenn inWerkzeug==0.14.1
eine Sicherheitslücke entdeckt wurde, die die Paketbetreuer sofort inWerkzeug==0.14.2
gepatcht haben? Sie müssen wirklich aufWerkzeug==0.14.2
aktualisieren, um Sicherheitsprobleme zu vermeiden, die sich aus der früheren, nicht gepatchten Version vonWerkzeug
ergeben.
Zunächst müssen Sie sich darüber im Klaren sein, dass ein Problem mit Ihrer Version vorliegt. Dann müssen Sie die neue Version in Ihrer Produktionsumgebung herunterladen, bevor jemand die Sicherheitslücke ausnutzt. Sie müssen also Ihrerequirements.txt
manuell ändern, um die neue VersionWerkzeug==0.14.2
anzugeben. Wie Sie in dieser Situation sehen können, liegt die Verantwortung, über die erforderlichen Aktualisierungen auf dem Laufenden zu bleiben, bei Ihnen.
Die Wahrheit ist, dass es Ihnen wirklich egal ist, welche Version vonWerkzeug
installiert wird, solange Ihr Code nicht beschädigt wird. Wahrscheinlich möchten Sie mit der neuesten Version sicherstellen, dass Sie Fehlerbehebungen, Sicherheitspatches, neue Funktionen, mehr Optimierung usw. erhalten.
Die eigentliche Frage lautet:“How do you allow for deterministic builds for your Python project without gaining the responsibility of updating versions of sub-dependencies?”
Spoiler-Alarm: Die einfache Antwort ist die Verwendung von Pipenv.
Entwicklung von Projekten mit unterschiedlichen Abhängigkeiten
Lassen Sie uns ein wenig die Gänge wechseln, um über ein weiteres häufiges Problem zu sprechen, das bei der Arbeit an mehreren Projekten auftritt. Stellen Sie sich vor, dassProjectA
django==1.9
benötigt,ProjectB
jedochdjango==1.10
benötigt.
Standardmäßig versucht Python, alle Pakete von Drittanbietern an einem systemweiten Speicherort zu speichern. Dies bedeutet, dass Sie jedes Mal, wenn Sie zwischenProjectA
undProjectB
wechseln möchten, sicherstellen müssen, dass die richtige Version vondjango
installiert ist. Dies macht das Wechseln zwischen Projekten schmerzhaft, da Sie Pakete deinstallieren und neu installieren müssen, um die Anforderungen für jedes Projekt zu erfüllen.
Die Standardlösung besteht darin,virtual environment zu verwenden, das über eine eigene ausführbare Python-Datei und einen Paketspeicher von Drittanbietern verfügt. Auf diese Weise werdenProjectA
undProjectB
angemessen getrennt. Jetzt können Sie problemlos zwischen Projekten wechseln, da diese nicht denselben Speicherort für Pakete verwenden. PackageA
kann jede Version vondjango
haben, die es in seiner eigenen Umgebung benötigt, undPackageB
kann das, was es braucht, völlig getrennt haben. Ein sehr verbreitetes Werkzeug hierfür istvirtualenv
(odervenv
in Python 3).
In Pipenv ist die Verwaltung virtueller Umgebungen integriert, sodass Sie ein einziges Tool für Ihre Paketverwaltung haben.
Abhängigkeitsauflösung
Was meine ich mit Abhängigkeitsauflösung? Angenommen, Sie haben einerequirements.txt
-Datei, die ungefähr so aussieht:
package_a
package_b
Angenommen,package_a
hat eine Unterabhängigkeitpackage_c
, undpackage_a
erfordert eine bestimmte Version dieses Pakets:package_c>=1.0
. package_b
hat wiederum die gleiche Unterabhängigkeit, benötigt jedochpackage_c<=2.0
.
Wenn Sie versuchen,package_a
undpackage_b
zu installieren, überprüft das Installationstool im Idealfall die Anforderungen fürpackage_c
(>=1.0
und<=2.0
) und wählt a aus Version, die diese Anforderungen erfüllt. Sie hoffen, dass das Tool die Abhängigkeiten auflöst, damit Ihr Programm am Ende funktioniert. Das meine ich mit "Abhängigkeitsauflösung".
Leider hat pip selbst im Moment keine echte Abhängigkeitsauflösung, aber es gibt einopen issue, um dies zu unterstützen.
Pip würde das obige Szenario wie folgt behandeln:
-
Es installiert
package_a
und sucht nach einer Version vonpackage_c
, die die erste Anforderung (package_c>=1.0
) erfüllt. -
Pip installiert dann die neueste Version von
package_c
, um diese Anforderung zu erfüllen. Angenommen, die neueste Version vonpackage_c
ist 3.1.
Hier beginnt das Problem (möglicherweise).
Wenn die von pip ausgewählte Version vonpackage_c
nicht den zukünftigen Anforderungen entspricht (z. B.package_b
, diepackage_c<=2.0
benötigen), schlägt die Installation fehl.
Die „Lösung“ für dieses Problem besteht darin, den für die Unterabhängigkeit (package_c
) erforderlichen Bereich in der Dateirequirements.txt
anzugeben. Auf diese Weise kann pip diesen Konflikt lösen und ein Paket installieren, das diese Anforderungen erfüllt:
package_c>=1.0,<=2.0
package_a
package_b
Wie zuvor beschäftigen Sie sich jetzt direkt mit Unterabhängigkeiten (package_c
). Das Problem dabei ist, dass wennpackage_a
ihre Anforderungen ohne Ihr Wissen ändert, die von Ihnen angegebenen Anforderungen (package_c>=1.0,<=2.0
) möglicherweise nicht mehr akzeptabel sind und die Installation möglicherweise erneut fehlschlägt. Das eigentliche Problem besteht darin, dass Sie erneut dafür verantwortlich sind, über die Anforderungen von Unterabhängigkeiten auf dem Laufenden zu bleiben.
Im Idealfall ist Ihr Installationstool intelligent genug, um Pakete zu installieren, die alle Anforderungen erfüllen, ohne dass Sie explizit Unterabhängigkeitsversionen angeben.
Pipenv Einführung
Nachdem wir uns nun mit den Problemen befasst haben, wollen wir sehen, wie Pipenv sie löst.
Zuerst installieren wir es:
$ pip install pipenv
Sobald Sie dies getan haben, können Siepip
effektiv vergessen, da Pipenv im Wesentlichen als Ersatz fungiert. Außerdem werden zwei neue Dateien eingeführt,Pipfile
(dierequirements.txt
ersetzen sollen) undPipfile.lock
(die deterministische Builds ermöglichen).
Pipenv verwendetpip
undvirtualenv
unter der Haube, vereinfacht jedoch deren Verwendung mit einer einzigen Befehlszeilenschnittstelle.
Beispiel Verwendung
Beginnen wir mit der Erstellung Ihrer fantastischen Python-Anwendung. Erstellen Sie zunächst eine Shell in einer virtuellen Umgebung, um die Entwicklung dieser App zu isolieren:
$ pipenv shell
Dadurch wird eine virtuelle Umgebung erstellt, falls noch keine vorhanden ist. Pipenv erstellt alle Ihre virtuellen Umgebungen an einem Standardspeicherort. Wenn Sie das Standardverhalten von Pipenv ändern möchten, gibt es einigeenvironmental variables for configuration.
Sie können die Erstellung einer Python 2- oder 3-Umgebung mit den Argumenten--two
und--three
erzwingen. Andernfalls verwendet Pipenv alle Standardeinstellungen vonvirtualenv
.
Nebenbemerkung: Wenn Sie eine spezifischere Version von Python benötigen, können Sie ein
--python
-Argument mit der gewünschten Version angeben. Zum Beispiel:--python 3.6
Jetzt können Sie das benötigte Drittanbieterpaketflask
installieren. Oh, aber Sie wissen, dass Sie Version0.12.1
und nicht die neueste Version benötigen. Gehen Sie also vor und seien Sie genau:
$ pipenv install flask==0.12.1
In Ihrem Terminal sollte Folgendes angezeigt werden:
Adding flask==0.12.1 to Pipfile's [packages]...
Pipfile.lock not found, creating...
Sie werden feststellen, dass zwei Dateien erstellt werden,Pipfile
undPipfile.lock
. Wir werden uns diese in einer Sekunde genauer ansehen. Lassen Sie uns ein weiteres Paket eines Drittanbieters,numpy
, installieren, um die Zahlen zu ermitteln. Sie benötigen keine bestimmte Version, geben Sie also keine an:
$ pipenv install numpy
Wenn Sie etwas direkt von einem Versionskontrollsystem (VCS) installieren möchten, können Sie! Sie geben die Speicherorte ähnlich wie beipip
an. Gehen Sie beispielsweise wie folgt vor, um dierequests
-Bibliothek über die Versionskontrolle zu installieren:
$ pipenv install -e git+https://github.com/requests/requests.git#egg=requests
Beachten Sie das obige Argument-e
, um die Installation bearbeitbar zu machen. Derzeit istthis is requiredfür Pipenv erforderlich, um die Auflösung von Unterabhängigkeiten durchzuführen.
Nehmen wir an, Sie haben auch einige Komponententests für diese großartige Anwendung und möchtenpytest
verwenden, um sie auszuführen. Sie benötigenpytest
in der Produktion nicht, sodass Sie angeben können, dass diese Abhängigkeit nur für die Entwicklung mit dem Argument--dev
gilt:
$ pipenv install pytest --dev
Wenn Sie das Argument--dev
angeben, wird die Abhängigkeit an einer speziellen Stelle von[dev-packages]
inPipfile
abgelegt. Diese Entwicklungspakete werden nur installiert, wenn Sie das Argument--dev
mitpipenv install
angeben.
Die verschiedenen Abschnitte trennen Abhängigkeiten, die nur für die Entwicklung benötigt werden, von denen, die für die tatsächliche Funktionsweise des Basiscodes erforderlich sind. In der Regel wird dies mit zusätzlichen Anforderungsdateien wiedev-requirements.txt
odertest-requirements.txt
erreicht. Jetzt wird alles in einem einzigenPipfile
unter verschiedenen Abschnitten konsolidiert.
Angenommen, Sie haben alles in Ihrer lokalen Entwicklungsumgebung zum Laufen gebracht und sind bereit, es in die Produktion zu bringen. Dazu müssen Sie Ihre Umgebung sperren, damit Sie sicherstellen können, dass Sie dieselbe in der Produktion haben:
$ pipenv lock
Dadurch werden IhrePipfile.lock
erstellt / aktualisiert, die Sie niemals manuell bearbeiten müssen (und sollen). Sie sollten immer die generierte Datei verwenden.
Sobald Sie Ihren Code undPipfile.lock
in Ihrer Produktionsumgebung erhalten haben, sollten Sie die zuletzt aufgezeichnete erfolgreiche Umgebung installieren:
$ pipenv install --ignore-pipfile
Dies weist Pipenv an, diePipfile
für die Installation zu ignorieren und diePipfile.lock
zu verwenden. Angesichts dieserPipfile.lock
erstellt Pipenv genau dieselbe Umgebung, in der Siepipenv lock
, Unterabhängigkeiten und alle ausgeführt haben.
Die Sperrdatei ermöglicht deterministische Builds, indem ein Snapshot aller Versionen von Paketen in einer Umgebung erstellt wird (ähnlich dem Ergebnis vonpip freeze
).
Angenommen, ein anderer Entwickler möchte Ihren Code ergänzen. In dieser Situation würden sie den Code einschließlich derPipfile
abrufen und diesen Befehl verwenden:
$ pipenv install --dev
Dadurch werden alle für die Entwicklung erforderlichen Abhängigkeiten installiert, einschließlich der regulären Abhängigkeiten und derjenigen, die Sie mit dem Argument--dev
währendinstall
angegeben haben.
Wenn in der Pip-Datei keine genaue Version angegeben ist, bietet der Befehl
install
die Möglichkeit für Abhängigkeiten (und Unterabhängigkeiten), ihre Versionen zu aktualisieren.
Dies ist ein wichtiger Hinweis, da er einige der zuvor diskutierten Probleme löst. Nehmen wir zur Demonstration an, dass eine neue Version einer Ihrer Abhängigkeiten verfügbar ist. Da Sie keine bestimmte Version dieser Abhängigkeit benötigen, geben Sie inPipfile
keine genaue Version an. Wenn Siepipenv install
verwenden, wird die neue Version der Abhängigkeit in Ihrer Entwicklungsumgebung installiert.
Jetzt nehmen Sie Ihre Änderungen am Code vor und führen einige Tests durch, um sicherzustellen, dass alles noch wie erwartet funktioniert. (Sie haben Unit-Tests, richtig?) Jetzt sperren Sie wie zuvor Ihre Umgebung mitpipenv lock
, und mit der neuen Version der Abhängigkeit wird ein aktualisiertesPipfile.lock
generiert. Nach wie vor können Sie diese neue Umgebung in der Produktion mit der Sperrdatei replizieren.
Wie Sie in diesem Szenario sehen können, müssen Sie keine genauen Versionen mehr erzwingen, die Sie nicht wirklich benötigen, um sicherzustellen, dass Ihre Entwicklungs- und Produktionsumgebungen identisch sind. Sie müssen sich auch nicht über die Aktualisierung von Unterabhängigkeiten auf dem Laufenden halten, die Ihnen "egal" sind. Dieser Workflow mit Pipenv in Kombination mit Ihren hervorragenden Tests behebt die Probleme bei der manuellen Durchführung des gesamten Abhängigkeitsmanagements.
Pipenvs Ansatz zur Lösung von Abhängigkeiten
Pipenv wird versuchen, Unterabhängigkeiten zu installieren, die alle Anforderungen Ihrer Kernabhängigkeiten erfüllen. Wenn jedoch widersprüchliche Abhängigkeiten bestehen (package_a
benötigtpackage_c>=1.0
,package_b
benötigtpackage_c<1.0
), kann Pipenv keine Sperrdatei erstellen und gibt einen Fehler wie aus folgende:
Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies. You can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation. Could not find a version that matches package_c>=1.0,package_c<1.0
Wie in der Warnung angegeben, können Sie auch ein Abhängigkeitsdiagramm anzeigen, um Ihre Abhängigkeiten der obersten Ebene und ihre Unterabhängigkeiten zu verstehen:
$ pipenv graph
Dieser Befehl druckt eine baumartige Struktur aus, in der Ihre Abhängigkeiten angezeigt werden. Hier ist ein Beispiel:
Flask==0.12.1 - click [required: >=2.0, installed: 6.7] - itsdangerous [required: >=0.21, installed: 0.24] - Jinja2 [required: >=2.4, installed: 2.10] - MarkupSafe [required: >=0.23, installed: 1.0] - Werkzeug [required: >=0.7, installed: 0.14.1] numpy==1.14.1 pytest==3.4.1 - attrs [required: >=17.2.0, installed: 17.4.0] - funcsigs [required: Any, installed: 1.0.2] - pluggy [required: <0.7,>=0.5, installed: 0.6.0] - py [required: >=1.5.0, installed: 1.5.2] - setuptools [required: Any, installed: 38.5.1] - six [required: >=1.10.0, installed: 1.11.0] requests==2.18.4 - certifi [required: >=2017.4.17, installed: 2018.1.18] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.7, installed: 2.6] - urllib3 [required: <1.23,>=1.21.1, installed: 1.22]
Aus der Ausgabe vonpipenv graph
können Sie die zuvor installierten Abhängigkeiten der obersten Ebene (Flask
,numpy
,pytest
undrequests
) und darunter erkennen Sie können die Pakete sehen, von denen sie abhängen.
Darüber hinaus können Sie den Baum umkehren, um die Unterabhängigkeiten mit dem übergeordneten Element anzuzeigen, für das dies erforderlich ist:
$ pipenv graph --reverse
Dieser umgekehrte Baum kann nützlicher sein, wenn Sie versuchen, widersprüchliche Unterabhängigkeiten herauszufinden.
Das Pipfile
Pipfile beabsichtigt,requirements.txt
zu ersetzen. Pipenv ist derzeit die Referenzimplementierung für die Verwendung vonPipfile
. Es scheint sehr wahrscheinlich, dasspip
itself will be able to handle these files. Es ist auch erwähnenswert, dassPipenv is even the official package management tool recommended by Python itself.
Die Syntax fürPipfile
lautetTOML, und die Datei ist in Abschnitte unterteilt. [dev-packages]
für Nur-Entwicklungs-Pakete,[packages]
für minimal erforderliche Pakete und[requires]
für andere Anforderungen wie eine bestimmte Version von Python. Siehe eine Beispieldatei unten:
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
pytest = "*"
[packages]
flask = "==0.12.1"
numpy = "*"
requests = {git = "https://github.com/requests/requests.git", editable = true}
[requires]
python_version = "3.6"
Idealerweise sollten Sie in IhrenPipfile
keine Unterabhängigkeiten haben. Damit meine ich, dass Sie nur die Pakete einschließen sollten, die Sie tatsächlich importieren und verwenden. Sie müssenchardet
nicht inPipfile
behalten, nur weil es sich um eine Unterabhängigkeit vonrequests
handelt. (Pipenv installiert es automatisch.) DiePipfile
sollten die Abhängigkeiten der obersten Ebene enthalten, die Ihr Paket benötigt.
Das Pipfile.lock
Diese Datei ermöglicht deterministische Builds, indem die genauen Anforderungen für die Reproduktion einer Umgebung angegeben werden. Es enthält genaue Versionen für Pakete und Hashes, um eine sicherere Überprüfung zu unterstützen, auchpip
itself now supports. Eine Beispieldatei könnte wie folgt aussehen. Beachten Sie, dass die Syntax für diese Datei JSON lautet und dass ich Teile der Datei mit...
ausgeschlossen habe:
{
"_meta": {
...
},
"default": {
"flask": {
"hashes": [
"sha256:6c3130c8927109a08225993e4e503de4ac4f2678678ae211b33b519c622a7242",
"sha256:9dce4b6bfbb5b062181d3f7da8f727ff70c1156cbb4024351eafd426deb5fb88"
],
"version": "==0.12.1"
},
"requests": {
"editable": true,
"git": "https://github.com/requests/requests.git",
"ref": "4ea09e49f7d518d365e7c6f7ff6ed9ca70d6ec2e"
},
"werkzeug": {
"hashes": [
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b",
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c"
],
"version": "==0.14.1"
}
...
},
"develop": {
"pytest": {
"hashes": [
"sha256:8970e25181e15ab14ae895599a0a0e0ade7d1f1c4c8ca1072ce16f25526a184d",
"sha256:9ddcb879c8cc859d2540204b5399011f842e5e8823674bf429f70ada281b3cc6"
],
"version": "==3.4.1"
},
...
}
}
Notieren Sie die genaue Version, die für jede Abhängigkeit angegeben wurde. Sogar die Unterabhängigkeiten wiewerkzeug
, die nicht in unserenPipfile
enthalten sind, erscheinen in diesenPipfile.lock
. Die Hashes werden verwendet, um sicherzustellen, dass Sie dasselbe Paket abrufen wie in der Entwicklung.
Es ist noch einmal erwähnenswert, dass Sie diese Datei niemals von Hand ändern sollten. Es soll mitpipenv lock
erzeugt werden.
Pipenv Extra Features
Öffnen Sie ein Paket eines Drittanbieters in Ihrem Standardeditor mit dem folgenden Befehl:
$ pipenv open flask
Dadurch wird das Paketflask
im Standardeditor geöffnet, oder Sie können ein Programm mit der UmgebungsvariablenEDITOR
angeben. Zum Beispiel verwende ichSublime Text, also setze ich nurEDITOR=subl
. Auf diese Weise können Sie ganz einfach in die Interna eines von Ihnen verwendeten Pakets eintauchen.
Sie können einen Befehl in der virtuellen Umgebung ausführen, ohne eine Shell zu starten:
$ pipenv run
Überprüfen Sie Ihre Umgebung auf Sicherheitslücken (und die Anforderungen vonPEP 508):
$ pipenv check
Angenommen, Sie benötigen kein Paket mehr. Sie können es deinstallieren:
$ pipenv uninstall numpy
Angenommen, Sie möchten alle installierten Pakete vollständig aus Ihrer virtuellen Umgebung löschen:
$ pipenv uninstall --all
Sie können--all
durch--all-dev
ersetzen, um nur Entwicklungspakete zu entfernen.
Pipenv unterstützt das automatische Laden von Umgebungsvariablen, wenn eine.env
-Datei im Verzeichnis der obersten Ebene vorhanden ist. Auf diese Weise werden beim Öffnen der virtuellen Umgebungpipenv shell
Ihre Umgebungsvariablen aus der Datei geladen. Die.env
-Datei enthält nur Schlüssel-Wert-Paare:
SOME_ENV_CONFIG=some_value
SOME_OTHER_ENV_CONFIG=some_other_value
Zum Schluss hier ein paar schnelle Befehle, um herauszufinden, wo sich etwas befindet. So finden Sie heraus, wo sich Ihre virtuelle Umgebung befindet:
$ pipenv --venv
So finden Sie heraus, wo sich Ihr Projekt befindet:
$ pipenv --where
Paketverteilung
Möglicherweise fragen Sie, wie dies alles funktioniert, wenn Sie Ihren Code als Paket verteilen möchten.
Ja, ich muss meinen Code als Paket verteilen
Wie funktioniert Pipenv mitsetup.py
Dateien?
Diese Frage hat viele Nuancen. Erstens ist einesetup.py
-Datei erforderlich, wenn Siesetuptools
als Build- / Verteilungssystem verwenden. Dies ist seit einiger Zeit der De-facto-Standard, aberrecent changes haben die Verwendung vonsetuptools
optional gemacht.
Dies bedeutet, dass Projekte wieflit die neuenpyproject.toml
verwenden können, um ein anderes Build-System anzugeben, für das keinesetup.py
erforderlich sind.
Alles, was gesagt wird, wird für die nahe Zukunftsetuptools
und ein begleitendessetup.py
für viele Menschen immer noch die Standardauswahl sein.
Hier ist ein empfohlener Workflow für den Fall, dass Siesetup.py
verwenden, um Ihr Paket zu verteilen:
-
setup.py
-
Das Schlüsselwort
install_requires
ollte das Paket“minimally needs to run correctly.”enthalten -
Pipfile
-
Stellt die konkreten Anforderungen für Ihr Paket dar
-
Ziehen Sie die minimal erforderlichen Abhängigkeiten von
setup.py
, indem Sie Ihr Paket mit Pipenv installieren:-
Verwenden Sie
pipenv install '-e .'
-
Dies führt zu einer Zeile in
Pipfile
, die ungefähr wie"e1839a8" = {path = ".", editable = true}
aussieht.
-
-
Pipfile.lock
-
Details für eine reproduzierbare Umgebung, generiert aus
pipenv lock
Geben Sie zur Verdeutlichung Ihre Mindestanforderungen insetup.py
anstatt direkt inpipenv install
ein. Verwenden Sie dann den Befehlpipenv install '-e .'
, um Ihr Paket als bearbeitbar zu installieren. Dadurch werden alle Anforderungen vonsetup.py
in Ihre Umgebung übertragen. Dann können Siepipenv lock
verwenden, um eine reproduzierbare Umgebung zu erhalten.
Ich muss meinen Code nicht als Paket verteilen
Toll! Wenn Sie eine Anwendung entwickeln, die nicht verteilt oder installiert werden soll (eine persönliche Website, eine Desktop-Anwendung, ein Spiel oder ähnliches), benötigen Sie keinesetup.py
.
In dieser Situation können Sie die KombinationPipfile
/Pipfile.lock
verwenden, um Ihre Abhängigkeiten mit dem zuvor beschriebenen Ablauf zu verwalten und eine reproduzierbare Umgebung in der Produktion bereitzustellen.
Ich habe bereits einrequirements.txt
. Wie konvertiere ich inPipfile
?
Wenn Siepipenv install
ausführen, sollte es automatischrequirements.txt
erkennen und inPipfile
konvertieren, wobei Folgendes ausgegeben wird:
requirements.txt found, instead of Pipfile! Converting… Warning: Your Pipfile now contains pinned versions, if your requirements.txt did. We recommend updating your Pipfile to specify the "*" version, instead.
Beachten Sie die obige Warnung.
Wenn Sie genaue Versionen in Ihrerrequirements.txt
-Datei angeheftet haben, möchten Sie wahrscheinlich IhrePipfile
ändern, um nur die genauen Versionen anzugeben, die Sie wirklich benötigen. Auf diese Weise können Sie die tatsächlichen Vorteile eines Übergangs nutzen. Angenommen, Sie haben Folgendes, benötigen jedoch nicht genau die Version vonnumpy
:
[packages]
numpy = "==1.14.1"
Wenn Sie keine spezifischen Versionsanforderungen für Ihre Abhängigkeiten haben, können Sie Pipenv mit dem Platzhalterzeichen*
mitteilen, dass jede Version installiert werden kann:
[packages]
numpy = "*"
Wenn Sie nervös sind, eine Version mit*
zuzulassen, ist es normalerweise eine sichere Sache, eine Version anzugeben, die größer oder gleich der Version ist, auf der Sie bereits sind, damit Sie weiterhin von neuen Versionen profitieren können:
[packages]
numpy = ">=1.14.1"
Wenn Sie über neue Versionen auf dem Laufenden bleiben, müssen Sie natürlich auch sicherstellen, dass Ihr Code bei Änderungen der Pakete weiterhin wie erwartet funktioniert. Dies bedeutet, dass eine Testsuite für diesen gesamten Pipenv-Ablauf unerlässlich ist, wenn Sie funktionierende Versionen Ihres Codes sicherstellen möchten.
Sie lassen Pakete aktualisieren, führen Ihre Tests aus, stellen sicher, dass sie alle erfolgreich sind, sperren Ihre Umgebung und können sich dann darauf verlassen, dass Sie keine wichtigen Änderungen vorgenommen haben. Wenn aufgrund einer Abhängigkeit Probleme auftreten, müssen Sie einige Regressionstests schreiben und möglicherweise weitere Einschränkungen für Versionen von Abhängigkeiten festlegen.
Wenn beispielsweisenumpy==1.15
nach dem Ausführen vonpipenv install
installiert wird und Ihr Code beschädigt wird, was Sie hoffentlich entweder während der Entwicklung oder während Ihrer Tests bemerken, haben Sie mehrere Möglichkeiten:
-
Aktualisieren Sie Ihren Code, um mit der neuen Version der Abhängigkeit zu funktionieren.
Wenn die Abwärtskompatibilität mit früheren Versionen der Abhängigkeit nicht möglich ist, müssen Sie auch die erforderliche Version in
Pipfile
eingeben:[packages] numpy = ">=1.15"
-
Beschränken Sie die Version der Abhängigkeit in
Pipfile
auf<
, die Version, die gerade Ihren Code beschädigt hat:[packages] numpy = ">=1.14.1,<1.15"
Option 1 wird bevorzugt, da dadurch sichergestellt wird, dass Ihr Code die aktuellsten Abhängigkeiten verwendet. Option 2 benötigt jedoch weniger Zeit und erfordert keine Codeänderungen, sondern nur Einschränkungen für Abhängigkeiten.
Sie können auch aus Anforderungsdateien mit demselben-r
Argumentpip
installieren:
$ pipenv install -r requirements.txt
Wenn Sie eindev-requirements.txt
oder ähnliches haben, können Sie diese auch zu denPipfile
hinzufügen. Fügen Sie einfach das Argument--dev
hinzu, damit es in den richtigen Abschnitt eingefügt wird:
$ pipenv install -r dev-requirements.txt --dev
Darüber hinaus können Sie in die andere Richtung gehen und Anforderungsdateien ausPipfile
generieren:
$ pipenv lock -r > requirements.txt
$ pipenv lock -r -d > dev-requirements.txt
Was kommt als nächstes?
Es scheint mir, dass ein natürlicher Fortschritt für das Python-Ökosystem ein Build-System wäre, dasPipfile
verwendet, um die minimal erforderlichen Abhängigkeiten beim Abrufen und Erstellen eines Pakets aus einem Paketindex (wie PyPI) zu installieren. Es ist wichtig zu beachten, dass sichPipfile design specification noch in der Entwicklung befindet und Pipenv nur eine Referenzimplementierung ist.
Davon abgesehen könnte ich eine Zukunft sehen, in der der Abschnittinstall_requires
vonsetup.py
nicht existiert und stattdessen aufPipfile
für minimale Anforderungen verwiesen wird. Oder diesetup.py
sind vollständig verschwunden, und Sie erhalten Metadaten und andere Informationen auf andere Weise, wobei Sie immer noch diePipfile
verwenden, um die erforderlichen Abhängigkeiten zu erhalten.
Lohnt es sich, Pipenv zu besuchen?
Bestimmt. Auch wenn dies nur eine Möglichkeit ist, die bereits verwendeten Tools (pip
&virtualenv
) in einer einzigen Oberfläche zusammenzufassen. Es ist jedoch viel mehr als das. Mit dem Hinzufügen vonPipfile
geben Sie nur die Abhängigkeiten an, die Sie wirklich benötigen.
Sie haben nicht mehr die Mühe, die Versionen von allem selbst zu verwalten, nur um sicherzustellen, dass Sie Ihre Entwicklungsumgebung replizieren können. Mit denPipfile.lock
können Sie sich beruhigt entwickeln und wissen, dass Sie Ihre Umgebung überall exakt reproduzieren können.
Darüber hinaus ist es sehr wahrscheinlich, dass dasPipfile
-Format von offiziellen Python-Tools wiepip
übernommen und unterstützt wird. Es wäre also von Vorteil, dem Spiel voraus zu sein. Oh, und stellen Sie sicher, dass Sie Ihren gesamten Code auch auf Python 3 aktualisieren:2020 is coming up fast.
Referenzen, weiterführende Literatur, interessante Diskussionen und so weiter
Free Bonus:Click here to get access to a free 5-day class zeigt Ihnen, wie Sie häufige Probleme mit dem Abhängigkeitsmanagement mit Tools wie Pip, PyPI, Virtualenv und Anforderungsdateien vermeiden können.