Pipenv: Eine Anleitung zum neuen Python Packaging Tool

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 vonflaskin eine Datei vonrequirements.txtaufzunehmen:

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.txtaus. 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.txtetwas spezifischer zu sein. Sie fügen der Abhängigkeit vonflaskversion specifier hinzu. Dies wird auch alspinning-Abhängigkeit bezeichnet:

flask==0.12.1

Durch das Anheften der Abhängigkeit vonflaskan 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). flaskelbst 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, dassProjectAdjango==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:

  1. Es installiertpackage_a und sucht nach einer Version vonpackage_c, die die erste Anforderung (package_c>=1.0) erfüllt.

  2. Pip installiert dann die neueste Version vonpackage_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_cnicht den zukünftigen Anforderungen entspricht (z. B.package_b, diepackage_c<=2.0benö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--devgilt:

$ pipenv install pytest --dev

Wenn Sie das Argument--devangeben, 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.lockerstellt / 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 Befehlinstall 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 inPipfilekeine 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_abenötigtpackage_c>=1.0,package_bbenö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 IhrenPipfilekeine 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 Paketflaskim Standardeditor geöffnet, oder Sie können ein Programm mit der UmgebungsvariablenEDITORangeben. 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üsselwortinstall_requiresollte 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 vonsetup.py, indem Sie Ihr Paket mit Pipenv installieren:

    • Verwenden Siepipenv install '-e .'

    • Dies führt zu einer Zeile inPipfile, die ungefähr wie"e1839a8" = {path = ".", editable = true} aussieht.

  • Pipfile.lock

  • Details für eine reproduzierbare Umgebung, generiert auspipenv 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:

  1. 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 inPipfile eingeben:

    [packages]
    numpy = ">=1.15"
  2. Beschränken Sie die Version der Abhängigkeit inPipfile 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.txtoder ähnliches haben, können Sie diese auch zu denPipfilehinzufügen. Fügen Sie einfach das Argument--devhinzu, 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, dasPipfileverwendet, 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.