Hacken von maya
Ich habe einige Lektionen gelernt, die zu meinem folgenden Vorschlag der empfohlenen Verwendung von pipenv
in Python-Bibliotheken führten. Ich erwarte, dass andere den Vorschlag überprüfen, und wenn wir eine Einigung erzielen, könnte der (aktualisierte) Text in pipenv
Dokumenten enden.
pipenv
Muster und Antimuster für das Python-BibliotheksprojektBEARBEITEN
Folgendes gilt am besten für allgemeine (meist Open Source) Python-Bibliotheken, die auf verschiedenen Python-Versionen und Betriebssystemen laufen sollen. Bibliotheken, die in einer strikten Enterprise-Umgebung entwickelt wurden, können unterschiedlich sein (achten Sie auf jeden Fall darauf, alle Abschnitte zu Problemen zu lesen).
ENDE DER BEARBEITUNG
TL;DR : Das Hinzufügen von pipenv
Dateien zum Python-Bibliotheksprojekt führt wahrscheinlich zu zusätzlicher Komplexität und kann einige Fehler verbergen, während der Bibliothekssicherheit nichts hinzugefügt wird. Halten Sie aus diesem Grund
Sie können die volle Leistung von pipenv
unabhängig davon, welche Dateien sich in .gitignore
.
Mit Python- Bibliothek meine ich ein Projekt mit normalerweise setup.py
, das auf die Verteilung und Verwendung auf verschiedenen Plattformen ausgerichtet ist, die sich in Python-Version und / oder Betriebssystem unterscheiden.
Beispiele sind maya
, requests
, flask
usw.
Auf der anderen Seite (keine Python-Bibliothek) gibt es Anwendungen, die auf bestimmte Python-Interpreter und Betriebssysteme ausgerichtet sind und oft in einer streng konsistenten Umgebung bereitgestellt werden.
pipfile
beschreibt diese Unterschiede sehr gut in Pipfile vs setup.py .
pipenv
(Bereitstellungstool)Ich stimme der Aussage voll und ganz zu, dass pipenv
ein Bereitstellungstool ist, da es Folgendes ermöglicht:
Pipfile.lock
) für die Bereitstellung der virtuellen UmgebungEs hilft, wenn man eine Anwendung bereitstellen oder in einer Python-Umgebung entwickeln muss, die über mehrere Entwickler hinweg sehr konsistent ist.
pipenv
Paketierungstool aufzurufen ist irreführend, wenn man davon ausgeht, dass es Python-Bibliotheken erstellt oder tief in deren Erstellung beteiligt ist. Ja, pipenv
kann viel helfen (bei der lokalen Entwicklung von Bibliotheken), kann aber möglicherweise schaden (oft bei CI-Tests, wenn es ohne tiefere Überlegung verwendet wird).
TL;DR : pipenv
bietet eine sichere Umgebung, indem genehmigte konkrete Abhängigkeiten angewendet werden, die in der Datei Pipfile.lock
, und die Python-Bibliothek darf nur abstrakte Abhängigkeiten definieren (also kann Pipfile.lock
nicht bereitstellen).
pipenv
glänzt in Bereitstellungsszenarien, die diesen Schritten folgen:
Pipfile
)Pipfile.lock
Pipfile.lock
als Definition einer genehmigten Python-Umgebung freigebenpipenv sync
, um "das goldene" Pipfile.lock
anderswo anzuwenden, um eine identische Python-Umgebung zu erhalten.Mit der Entwicklung von Python-Bibliotheken kann man eine solche Sicherheit nicht erreichen, da Bibliotheken keine konkreten Abhängigkeiten definieren müssen . Das Brechen dieser Regel (also der Versuch, konkrete Abhängigkeiten durch die Python-Bibliothek zu deklarieren) führt zu Problemen wie:
setup.py
definierter Abhängigkeitensetup.py
soll alle abstrakten Abhängigkeiten über install_requires
.
Wenn Pipfile
diese Abhängigkeiten definiert, können Probleme wie:
install_requires
Pipfile
definiert bestimmte Regeln (Versionsbereiche etc.) für eine Abhängigkeit und install_requires
nicht.Um dies zu verhindern, befolgen Sie diese Regeln:
Pipfile
[packages]
in Pipfile
soll entweder leer sein oder nur eine einzelne Abhängigkeit von der Bibliothek selbst definieren.Pipfile.lock
im RepositoryEs ist falsch, Pipfile.lock
(normalerweise aus "Sicherheitsgründen") im Bibliotheksrepository zu behalten, weil:
Um dies zu verhindern, sollte man:
Pipfile.lock
aus dem Repository und füge es zu .gitignore
tox
(versteckt usedevelop
)Wenn tox.ini
in seinem Abschnitt commands
Einträge enthält wie:
pipenv install
pipenv install --dev
pipenv lock
es ist oft ein Problem, denn:
pipenv install
soll nur die Bibliothek selbst installieren und tox
tut dies (standardmäßig) auch. Abgesehen von Duplizität verhindert es auch usedevelop=True
und usedevelop=False
in tox.ini
weil Pipenv
es nur in einer Variante ausdrücken kann (und tox.ini
erlaubt Unterschiede in verschiedenen Umgebungen).Um dies zu verhindern, sollte man:
pipenv
in tox.ini
. Siehe Anfragen tox.inipipenv
fehlschlägtpipenv
befindet sich in der Entwicklungsphase und die Dinge gehen irgendwann kaputt. Wenn ein solches Problem Ihren CI-Build unterbricht, gibt es einen Fehler, der verhindert werden könnte, indem Sie pipenv
und traditionelle Tools (die oft etwas ausgereifter sind) verwenden.
Um dies zu verhindern, sollte man:
pipenv
in ein CI-Build-Skript, tox.ini
oder ähnliches einfügen. Wissen Sie, welchen Wert Sie durch das Hinzufügen erhalten? Könnte die Arbeit mit vorhandenen Werkzeugen erledigt werden?Die wichtigsten Fragen zur Rolle von pipenv
bei der Entwicklung der Python-Bibliothek sind:
pipenv
wirklich? A: Virtualenv-Verwaltungstool.pipenv
? A: Virtualenv verwalten.Einige weitere Details und Tricks folgen.
pipenv
fügt Ihrem Paket keine Sicherheit hinzuSchieben Sie es nicht ins Projekt, nur weil es jeder macht oder weil Sie zusätzliche Sicherheit erwarten. Es wird dich enttäuschen.
Die Absicherung durch konkrete (und genehmigte) Abhängigkeiten erfolgt in einer späteren Phase des Antrags auf Nutzung Ihrer Bibliothek.
Pipfile
, Pipfile.lock
und .env
Dateien aus dem Repository fernLegen Sie die Dateien in .gitignore
.
Pipfile
sich leicht nachbauen, wie unten gezeigt, da die meisten oder alle Anforderungen bereits in Ihrem setup.py
. Und die Datei .env
enthält wahrscheinlich private Informationen, die nicht weitergegeben werden sollen.
Wenn Sie diese Dateien aus dem Repository heraushalten, werden alle Probleme vermieden, die bei CI-Builds auftreten können, wenn pipenv
in Situationen verwendet wird, die nicht angemessen sind.
pipenv
als private Toolbox des Entwicklerspipenv
kann die Arbeit des Entwicklers als Virtualenv-Verwaltungstool vereinfachen.
Der Trick besteht darin, zu lernen, wie Sie Ihre (privaten) pipenv
bezogenen Dateien schnell neu erstellen können, zB:
$ cd <project_repository>
$ # your library will bring the dependencies (via install_requires in setup.py)
$ pipenv install -e .
$ # add more dev tools you preffer
$ pipenv install --dev ipython pdbpp
$ # start hacking
$ pipenv shell
...
Verwenden Sie die Datei .env
, wenn Sie eine bequeme Methode zum Einrichten von Umgebungsvariablen benötigen.
Denken Sie daran: Halten Sie die Nutzung von pipenv
aus Ihren CI-Builds heraus und Ihr Leben wird einfacher.
setup.py
, um Abhängigkeiten von Extras zu deklarierenVerwenden Sie in Ihrem setup.py
den Abschnitt extras_requires
:
from setuptools import setup
setup(
name='mypackage',
....,
install_requires=["jinja2", "simplejson"],
extras_require={
'tests': ['pytest', 'pyyaml'],
'pg': ['psycopg2'],
},
....
)
Um alle für tests
deklarierten Abhängigkeiten zu installieren:
$ pipenv install -e .[tests]
Beachten Sie, dass es immer die install_requires
Abhängigkeiten enthält.
Diese Methode erlaubt es nicht, Abhängigkeiten in Default- und Dev-Abschnitte aufzuteilen, aber dies sollte in erwarteten Szenarien kein wirkliches Problem darstellen.
Das ist sehr beeindruckend, vielen Dank fürs Kompilieren. Werde auf jeden Fall in Kürze genauer rezensieren
/cc @uranusjr @jtratner @ncoghlan
Einige Hinweise auf maya
Probleme:
pendulum>=1.0
in setup.py: Version war in Pipfile aber fehlte in setup.py)pipenv
Problem den ganzen Travis-Lauf brach)Ich liebe das auch. Vielleicht sollten wir dies der Dokumentation von Pipenv oder sogar dem Python Packaging User Guide hinzufügen.
Die Folge der obigen Ratschläge scheint zu sein, "auf deterministische/reproduzierbare CI-Builds zu verzichten", was mir als sehr großes Anti-Muster erscheint.
Was schlagen Sie als Alternative vor, die noch Determinismus zulassen würde?
@tsiq-oliverc Deterministische Builds haben im Moment ihren Platz, eine Anwendung soll gebaut werden.
Stellen Sie sich den folgenden Versuch vor, wirklich deterministische Builds der Python-Bibliothek durchzuführen:
Pipfile.lock
basierenPipfile.lock
die sich aus den abstrakten Bibliotheksabhängigkeiten ergeben, die in Pipfile
Pipfile.lock
Instanzen bereitstellen, die im Repository definiert sind. Beachten Sie, dass das automatische Erstellen von Pipfile.lock
während des CI-Builds keinen Determinismus hinzufügtDas ist ein großer zusätzlicher Aufwand. Und was Sie bekommen, ist eine Bibliothek, die in einem anderen Kontext installiert wird (zB eine Woche später wird die Standardinstallation aktualisierte Abhängigkeiten oder zwei aufnehmen) und die nichts davon bekommt, dass Sie Pipfile.lock
, was ist im Moment obsolet.
Der Konflikt besteht darin, dass die Bibliothek niemals strenge Abhängigkeiten im Inneren definieren darf.
Wenn Sie denken, gibt es eine andere Alternative, um deterministische Builds für die Python-Bibliothek zu erhalten - beschreiben Sie sie.
@vlcinsky - Wenn ein Verbraucher Ihrer Bibliothek verschiedene Versionen von Abhängigkeiten usw. verwendet, liegt dies außerhalb Ihrer Kontrolle. Ich stimme also zu, dass es für einen Bibliotheksverwalter keinen praktikablen Weg gibt, dies zu verwalten.
Aber das Ziel ist hier vermutlich ein viel kleinerer Spielraum. Insbesondere würde ich die Ziele für einen Bibliotheksverwalter wie folgt sehen (was ungefähr Äquivalenzen sind):
Wenn eines dieser drei Dinge nicht zutrifft, erscheint es mir im Gegensatz zur Qualitätskontrolle.
Also ja, ich würde sagen, wenn Sie Ihrem Verbraucher garantieren, die Python-Varianten A, B und C zu unterstützen, und sie sich so unterschiedlich verhalten, dass eine Sperrdatei (usw.) sie nicht schneidet, dann sollten Sie drei Sperrdateien (oder wie auch immer).
Ich habe Pipenv jedoch nicht genug verwendet, um zu wissen, wie einfach das in der Praxis wäre.
Ich überlege derzeit, Pipfile
s zu einigen Bibliotheksprojekten für das CI-System hinzuzufügen.
Das Dependency Locking (+Hashing) benötige ich unbedingt, um unternehmensweite Sicherheitsrichtlinien einzuhalten und muss derzeit nicht mit verschiedenen Python-Versionen testen, da nur eine offiziell unterstützt wird. Und dass pipenv das Einrichten einer lokalen Entwicklungsumgebung inklusive virtualenv vereinfacht, ist ein netter Nebeneffekt.
Und was Sie bekommen, ist eine Bibliothek, die in einem anderen Kontext installiert wird (zB eine Woche später wird die Standardinstallation aktualisierte Abhängigkeiten aufnehmen oder zwei) und die nichts davon bekommt, dass Sie
Pipfile.lock
, was ist im Moment obsolet.
Dies ist nicht allgemein wahr. In der Welt der Unternehmenssoftware gibt es immer noch sehr spezielle Umgebungen, die offiziell unterstützt werden, und ein Sicherheitsproblem in einer Abhängigkeit führt dazu, dass Ihr Produkt aktualisiert wird, anstatt dass der Kunde die Abhängigkeit selbst aktualisiert.
(Ja, ich rede hier von einer Bibliothek, nicht von einer Anwendung...)
@ Moritz90 Ihr Szenario ist für die Python-Bibliothek in einer Unternehmensumgebung und dort kann pipenv
helfen, da es sich um eine viel deterministischere Umgebung handelt.
Meine Beschreibung zielt auf allgemeine Python-Bibliotheken wie flask
, request
, maya
usw. ab, bei denen der Kontext viel variabler ist. Als ich versuchte, ein paar Dinge in maya
zu beheben, wurde ich frustriert, als ich lernte, dass die Verwendung von pipenv
in vielen Fällen echte Probleme mit sich brachte (normalerweise versteckte Probleme, die normalerweise erkannt würden), während nicht viel oder zusätzliches bereitgestellt wurde Wert.
Es ist eine gute Sache, deterministische Builds zu erhalten, aber es verursacht Kosten. Und wenn es falsch gemacht wird, können Sie für ein Ergebnis mit geringerer Qualität extra bezahlen - und das wollte ich verhindern.
Ich würde argumentieren, dass dies einer der Fälle ist, in denen die Builds nicht absolut deterministisch sein sollen. Wenn Sie Ihre Abhängigkeiten nicht mit ==
anheften, verpflichten Sie sich, standardmäßig mehrere Versionen zu unterstützen, und sollten die Bibliothek so gestalten. Ein Abhängigkeits-Upgrade, das den Build auf CI zerstört, ist eigentlich eine gute Sache, da es einen Fehler in der Bibliothek aufdeckt. Völlig deterministische Abhängigkeiten (wie von Pipenv verwaltet) würden dies maskieren. Es wäre immer noch von Vorteil, deterministisch sein zu können, wenn Sie es wollen, das ist im Allgemeinen nicht das Beste.
@uranusjr - Klar. Ich stimme zu, dass, wenn der Wunsch "nicht deterministische Builds" ist, der Rat oben durchaus sinnvoll sein kann. Tatsächlich ist es fast eine logische Äquivalenz und könnte viel prägnanter formuliert werden: "Wenn Sie keine deterministischen Builds möchten, verwenden Sie kein Tool ( pipenv
), dessen Zweck es ist, deterministische Builds zu gewährleisten." .
Aber das ist im Allgemeinen sicherlich kein wünschenswertes Ziel.
@tsiq-oliverc schöne Scope-Definition - sie unterstützt fokussierte Diskussionen. Ich möchte eine weitere Anforderung hinzufügen: Der CI-Determinismus soll mögliche Probleme innerhalb der getesteten Bibliothek nicht verbergen.
Wenn wir Pipenv.lock
, darauf basierend virtualenv erstellen und den CI-Test der Bibliothek ausführen, haben wir einen Teil der Funktionalität der Bibliothek ausgeführt - die Installation der richtigen Abhängigkeiten. Wenn die Bibliothek in dieser Hinsicht irgendwie kaputt ist, würde eine vorinstallierte Umgebung dieses Problem verbergen.
Mir scheint es wichtiger, Probleme innerhalb einer Bibliothek zu erkennen, als CI auf deterministische Weise auszuführen. Wenn es eine Möglichkeit gibt, beides zu tun (zB den Test hinter dem privaten Pypi-Index ausführen, der auch den Determinismus unterstützen könnte), habe ich kein Problem, aber wenn es einen Konflikt gibt, habe ich meine Prioritäten.
Verstehen Sie mich nicht falsch: Es besteht kein Wunsch, nicht-deterministische Builds auszuführen. Mein Wunsch ist es, CI-Builds auszuführen, die so viele Probleme wie möglich erkennen.
@vlcinsky Klar, ich wollte nur meine Erfahrungen teilen, um sicherzustellen, dass die aktualisierte Dokumentation dies auch widerspiegelt. Die aktuelle Dokumentation leistet hervorragende Arbeit, um die Kompromisse zu erklären:
Definieren Sie für Bibliotheken abstrakte Abhängigkeiten über install_requires in setup.py. […]
Definieren Sie für Anwendungen Abhängigkeiten und wo sie in der Pipfile abgerufen werden können, und verwenden Sie diese Datei, um den Satz konkreter Abhängigkeiten in Pipfile.lock zu aktualisieren. […]
Natürlich sind Pipfile und pipenv für Bibliotheksentwickler weiterhin nützlich, da sie zum Definieren einer Entwicklungs- oder Testumgebung verwendet werden können.
Und natürlich gibt es Projekte, bei denen die Unterscheidung zwischen Bibliothek und Anwendung nicht so klar ist.
(Der in meinem Fall zutreffende Teil ist hervorgehoben.)
Ich möchte nur sicherstellen, dass es so bleibt. Ich denke, Ihr ursprünglicher Beitrag enthält zu viele Pauschalaussagen ohne Haftungsausschluss, dass Sie von einem Open-Source-Projekt sprechen, das auf PyPI veröffentlicht wird.
@ Moritz90 Ich stimme
@ Moritz90 Ich habe eine einleitende Anmerkung hinzugefügt, die Ihren Kommentar widerspiegelt.
@vlcinsky - Das macht Sinn. Ich verstehe , dass Sie nicht explizit wollen nicht deterministisch bauen, aber ich denke , dass es unvermeidlich ist äquivalent zu dem, was Sie wollen zu tun (dh zu fangen Probleme , wenn Ihre Upstream - Abhängigkeiten Update).
Was ist der beste Weg, um diese beiden widersprüchlichen Ziele zu lösen? Eine Möglichkeit ist ein zweistufiger CI-Prozess:
Pipfile.lock
in Ihrem Repository, sodass es vollständig reproduzierbar ist.pipenv update
und führt dann die Tests aus, so dass die neuesten Ihrer Abhängigkeiten abgerufen werden (was im Grunde das gleiche ist wie das Verhalten ohne Sperrdatei, denke ich?).@tsiq-oliverc Um deterministische Builds zu erhalten, würde ich an folgendes Setup denken:
pipenv
Die Verwendung von pipenv
für die Installation ist ähnlich wie die Installation der Bibliothek selbst, aber es ist definitiv anders, weil es ein anderer Code ist, der die Arbeit erledigt.
$ git clone <repo_url> <project_dir>
$ cd <project_dir>
$ pip install pipenv
$ $ # clean pypi cache and make it ready to cache somehow - not described here
$ pipenv install -e .[test]
$ # if we need extra testing packages in pipenv
$ pipenv install <extra_test_packages>
$ # record current requirements expressed in `Pipfile.lock`
$ pipenv lock
$ # if needed, record the `Pipfile.lock` somewhere
Ausgaben eines solchen Jobs sind:
Pipfile.lock
als aufgezeichnete Abhängigkeiten (kann Entwicklern helfen, die Umgebung leicht zu reproduzieren)es gibt Phasen:
tox
, pip
usw. zu erzwingen, indem Sie nur unseren lokalen Pypi-Cache verwendenpipenv
)Pipfile.lock
zeichnet pypi-Pakete auf, die verwendet wurden, um die Bibliothek zu installieren. Es kann verwendet werden, um die Umgebung am Entwicklerstandort zu reproduzieren.Ein weiterer Vorteil ist, dass dieses Setup keine Entwickler benötigt, die Pipfile
oder Pipfile.lock
pflegen. Auch das Ausführen der Tests in verschiedenen Kontexten ist immer gleich ( Pipfile.lock
wird immer im gegebenen Kontext neu erstellt).
Der Pypi-Cache ist der Teil, der etwas Forschung erfordert. Ich denke, ein einfaches Verzeichnis würde ausreichen und vielleicht ist pipenv
bereits bereit, dabei zu helfen. Vielleicht ist Ausgabe #1731 der fehlende Teil.
Als Paket, das die Abhängigkeitsauflösung durchführt, verlassen sich viele unserer eigenen Tests auf deterministische Builds – das heißt, wir nehmen bekannte Dinge und erwarten einen aufgelösten Graphen. Dafür verwenden wir pytest-pypi
.
Ich liebe die lebhafte Diskussion zu diesem Thema. Ich denke, die Nuance ist wichtig und Sie sollten immer sowohl gegen bekannte als auch gegen nicht fixierte Abhängigkeiten testen
Sie sollten immer sowohl gegen bekannte als auch gegen ungepinnte Abhängigkeiten testen
Ich unterstütze diesen Vorschlag. Es ist eine gute Idee, immer einen expliziten "bekannten guten Zustand" für reproduzierbare Builds zu haben und das Debuggen zu vereinfachen, falls ein Update etwas kaputt macht, sowie sicherzustellen, dass neuere Neben-/Bugfix-Versionen ebenfalls funktionieren.
(Meiner ganz persönlichen Meinung nach wäre die Idealsituation, dass der Paketmanager standardmäßig die neuesten Minor-Versionen installiert, damit Bibliotheken immer die konkreten Abhängigkeitsversionen angeben können, mit denen sie getestet wurden, aber ich merke, das ist eine sehr umstrittene Meinung und erfordert jeden semver folgen.)
@Moritz90 @techalchemy @uranusjr @tsiq-oliverc
Hier ist meine Zusammenfassung aus der vorherigen Diskussion.
Pipfile.lock
Datei(en)?Jedes unterstützte Betriebssystem und Python-Interpreter trägt zur Matrix möglicher Ausführungskontexte bei.
ZB unterstützt Flask (zumindest CI-Sachen im Repository sichtbar):
Es macht 9 verschiedene Ausführungskontexte, die sich unterscheiden können.
Jeder Ausführungskontext kann unterschiedliche Pipfile.lock
.
Wer soll sie pflegen?
Optionen sind:
Pipfile.lock
für die Hauptentwicklungsplattform (welche Plattform wird gerne ignoriert?)Vorschlag: Lassen Sie CI die Datei mit pipenv install -e .
generieren. Fügen Sie es nicht in das Repo ein, helfen Sie Entwicklern, die richtigen Pipfile.lock
als Ergebnis automatisierter Builds auszuwählen.
Beim Beheben eines Problems, das durch Änderungen der Abhängigkeiten von pypi verursacht werden kann, benötigen Entwickler möglicherweise einfache Mittel, um die Umgebung aus dem fehlgeschlagenen Test zu reproduzieren.
Vorschlag:
Pipfile.lock
durch pipenv install -e .
gefolgt von pipenv lock
generieren.Pipfile.lock
aus dem fehlgeschlagenen Test aus.Pipfile.lock
in tox.ini
anwendet.setup.py
reveal aufdeckenDie Bibliothek setup.py
kann beschädigt sein (fehlende Abhängigkeit in install_requires
, fehlender Versionsspezifizierer usw.) und CI-Test darf ein solches Problem nicht verbergen (indem die ausgelassenen Abhängigkeiten selbst vorinstalliert werden).
Vorschlag:
pipenv install -e .
, um das gleiche Ergebnis wie bei der einfachen Installation zu erzielen (dabei gibt es derzeit einige Probleme).pipenv
) aus und vergleichen Sie möglicherweise, dass die resultierende Ausgabe von pip freeze
eine Teilmenge dessen ist, was von pipenv
installiert wird.Einige Abhängigkeitsaktualisierungen können die Bibliothek beschädigen, die sie verwendet. CI wird Fehler bei einem solchen Problem erkennen.
Vorschlag:
Pipfile.lock
generiert, ist dies kein Problem (da wir sowieso im nicht angehefteten Modus ausgeführt werden).In allen vorgeschlagenen Modi habe ich versucht zu vermeiden, dass pipenv
Dateien im Repository gespeichert werden, um Entwickler davon abzuhalten, dieses wirklich komplexe Zeug (Automatisierung!!!) zu pflegen.
Im Gegensatz zu meinem ursprünglichen Text verwenden der 2. und 3. Modus pipenv
in CI-Skripten.
Einfaches Paket mit einer geringeren Anzahl von Abhängigkeiten, die sich nicht oft ändern.
Laufen Sie einfach wie vor der Ära von pipenv
und halten Sie die Dinge für uns einfach.
Seltene Fälle, in denen Abhängigkeiten zu Problemen führen, sind leicht zu beheben und rechtfertigen keine komplexere CI.
Generieren Sie jedes Mal, wenn der CI-Test ausgeführt wird, ein neues Pipfile.lock
das die momentan verwendete Umgebung vollständig beschreibt.
Das Pipfile.lock
wird zum CI-Artefakt.
Wenn etwas schief geht, kann der Entwickler Pipfile.lock
aus einem defekten Build auswählen, ihn lokal anwenden und die Tests und Reparaturen durchführen.
Wenn jemand bereitstellen möchte, kann Pipfile.lock
aus dem letzten erfolgreichen Build verwendet werden.
Wenn das Ändern von Abhängigkeiten ein echtes Problem ist, erstellt CI einmal Pipfile.lock
und verwendet es für einen bestimmten Zeitraum (einen Monat?).
Dies erschwert das CI-Setup, da es mindestens zwei verschiedene Jobs geben muss (einer generiert Pipfile.lock
, der andere wendet ihn an und verwendet ihn in Tests).
Achtung: Pipfile.lock
muss auch aktuell aktualisiert werden, setup.py
ändert Abhängigkeiten.
Beachten Sie, dass für Ice Age Scrat der Eichhörnchen-Testtyp erforderlich ist, der den eingefrorenen Status ignoriert und gegen ungepinnte Versionen prüft.
Wie man sieht, wächst der Determinismus und die Komplexität von Modus zu Modus.
Mein Vorschlag wäre:
Alle Gewinne kosten etwas.
Wenn das Ziel hier darin besteht, die Ratschläge in den Dokumenten zu aktualisieren, dann fühlt es sich ehrlich gesagt unverantwortlich an, etwas dramatisch anderes zu sagen als "Befolgen Sie standardmäßig die Best Practices (reproduzierbare Builds), bis Sie keine andere Wahl haben".
@vlcinsky Unter der Überschrift "Modus: Generieren und versiegeln" kann es sinnvoll sein zu erwähnen, dass das letzte erfolgreiche Pipfile.lock
immer erhalten bleiben sollte, zB indem es als Jenkins-Artefakt deklariert wird. Mit dieser Änderung wäre es in Ordnung, dieses Setup für die meisten Projekte zu empfehlen. Wie @tsiq-oliverc würde ich den ersten Modus überhaupt nicht empfehlen.
Je mehr ich darüber nachdenke, desto mehr habe ich das Gefühl, dass diese Dokumentation ein Abschnitt darüber wird, warum die Verwendung von pipenv
für CI-Builds eine großartige Idee ist, selbst wenn Sie eine Bibliothek entwickeln.
@tsiq-oliverc Die überwiegende Mehrheit der allgemeinen Python-Pakete befindet sich im Modus "Run, Forrest, Run". Ich habe einigen dieser Pakete bei der Einführung von tox
und pytest
geholfen, weil ich der Meinung war, dass dies zu einer gegebenen Paketqualität beitragen würde und weil ich eine ziemlich klare Vorstellung hatte, wie es gut gemacht werden könnte.
Jetzt gibt es ein weiteres großartiges Tool und ich frage mich, wie man pipenv
in allgemeinen Python-Projekten richtig einsetzt, um zur Qualität beizutragen. Ich möchte ein oder zwei gut funktionierende Rezepte finden, die gerechtfertigt und leicht zu befolgen sind.
Was würde ich zum Flask-Projekt sagen?
Pipfile.lock
Dateien hinzufügen und Richtlinien für deren Aktualisierung einrichten?Pipfile.lock
Artefakte für Fälle zu generieren, in denen jemand einen fehlgeschlagenen Test auf seinem eigenen Computer reproduzieren muss?Ziel ist es, einen funktionalen Arbeitsstil zu finden. Wenn es auf doc endet, schön, wenn nicht, kein Problem.
@vlcinsky Ich würde sagen, (1) und (4) sollten die Empfehlung für solche Projekte sein. Während Sie ohne ein bereits vorhandenes Pipfile.lock
die im Build verwendeten Versionen nicht im Voraus kennen (was außerhalb von Unternehmensumgebungen in Ordnung ist), erhalten Sie dennoch ein reproduzierbares Ergebnis, wenn Sie die Sperrdatei generieren und archivieren während des Aufbaus.
Bearbeiten : Die tl; dr-Version meiner Empfehlung wäre:
pipenv
kann Ihnen dabei helfen, dieses Ziel zu erreichen.Pipfile.lock
in Ihr Repository und verwenden Sie es für die Bereitstellung. (Dies ist bereits durch die vorhandene Dokumentation abgedeckt.)Pipfile.lock
on-the-fly in Ihrem CI-Build und archivieren Sie es für später.(Natürlich sollte die eigentliche Dokumentation etwas mehr Details und Beispiele enthalten.)
@ Moritz90 Ich habe das "Generieren und Versiegeln" wie von Ihnen vorgeschlagen geändert.
Zu (1): leicht zu sagen, unmöglich auszuführen, ohne genauer zu sein.
Zu (4): ja, ich denke auch, dass "Generate and Seal" der praktikabelste Modus ist. Aber im Falle von Flask werde ich mich (zumindest im Moment nicht) nicht trauen.
Re vorhandene Pipfile.lock
in Unternehmensumgebungen: Es muss irgendwie erstellt werden, entweder (halb)manuell oder automatisch. Ich schätze, in einer Unternehmensumgebung installiert man nicht direkt von öffentlichen pypi, sondern verwendet ein privates, das nur genehmigte Pakete bereitstellt ( devpi-server
bietet dabei einen großartigen Service - mehrere Indizes, kontrollierte Volatilität veröffentlichter Pakete, Genehmigungen für externe Pakete usw.) Wenn der Prozess zum Erstellen von Pipfile.lock
in einer solchen Umgebung läuft, kann er nur das verwenden, was genehmigt wurde. Wenn also dort eine neue Version erscheinen soll, muss jemand aufstehen und sie genehmigt machen. Der folgende CI-Build wird testen, ob die Dinge nicht kaputt gehen. Und mit pipenv check
Test von Sicherheitsproblemen auch automatisiert werden.
Ich denke, ein solcher Workflow wäre sicherer als jemand, der ihn (halb) manuell erstellt. Aber mein Wissen über die Unternehmensumgebung ist sehr begrenzt.
Hallo Pipenv-Team. Ich teile viel von dem, was in diesem Text gesagt wird, es hilft jedem Entwickler, die Einschränkungen von Pipfile/pipenv beim Entwickeln einer Bibliothek besser zu verstehen. Ich möchte diesen Text oder einen Teil davon in die offizielle pipenv-Dokumentation integriert sehen.
Ich habe folgende Änderung, die ich gerne besprechen möchte:
Für unser internes Python - Paket, komplett wiederverwendbar, auf unserer internen pypi veröffentlicht, etc, und auch für meine eigenen Python - Pakete (zB: cfgtree , txrwlock , pipenv-to-Anforderungen ), verwende ich ein Paket , dass einige schon wissen oder sogar nutzen , das diese Details abstrahiert und das Leben von Python-Entwicklern einfacher macht: PBR.
PBR liest grundsätzlich requirements.txt
im Stammordner eines Distributionspakets und fügt es in das install_requires
des setup.py
. Der Entwickler muss lediglich ein requirements.txt
mit losen Abhängigkeitsdeklarationen pflegen. Bis die Unterstützung von Pipfile
offiziell in PBR integriert ist, muss ich pipenv-to-requirements verwenden , die automatisch requirements.txt
aus Pipfile
generieren, damit beide synchronisiert und beide festgeschrieben werden im Quellcode, und PBR führt die Injektion korrekt aus, nachdem das Verteilungspaket erstellt wurde. Ich denke, man könnte pipenv
, um dieses requirements.txt
zu generieren
Ich arbeite an einer Unterstützung von Pipfile für PBR, damit es die Pipfile
(und nicht die Sperrdatei) lesen und in install_requires
injizieren kann, wie es bei requirements.txt
Fall ist
Ich weiß nicht, ob es andere ähnliche Pakete gibt, weil es auch andere Dinge macht, die die Leute vielleicht nicht wollen (Version aus der Git-Historie, automatische Generierung von AUTHORS und ChangLog).
Aber am Ende finde ich es wirklich so einfacher, eine Python-Bibliothek zu schreiben, zu warten und zu verwalten, dass ich traurig wäre, diese Erfahrung nicht zu teilen. Ich bewerbe es als die "empfohlene" Art, moderne Python-Bibliotheken in meinem Unternehmen zu schreiben.
Ich vermute, dass es wie "Betrügen" bei allen Schwierigkeiten bezüglich Bibliothek und Pipenv ist, aber am Ende ist die Arbeit getan und die Entwickler sind glücklich, sie bis jetzt zu verwenden. Ein Teil des Python-Trainings, das ich neuen Python-Entwicklern in meinem Unternehmen gebe, beinhaltet, zuerst eine Python-Bibliothek zu schreiben, die install_requires
manuell verwaltet, und dann zu PBR
zu wechseln, um zu sehen, wie es einfacher wird ( und ehrlich gesagt bin ich ein Fan der semantischen Commit-Funktion von pbr, um automatisch das richtige Semver-Versions-Tag zu erstellen).
Ein Grund für die Deklaration der Bibliotheksabhängigkeiten mit einer dedizierten Datei auch für Bibliotheken ist die Möglichkeit, Tools wie readthedocs oder pyup verwenden zu können (auch wenn pyup mehr Sinn macht, wenn es mit einer Anwendung verknüpft wird).
Ich möchte diese Methode nicht unbedingt als "Standard"-Methode für Python-Pakete bewerben, es ist tatsächlich die "OpenStack" -Methode, aber ich würde meine Erfahrungen teilen, und wenn andere ähnliche oder widersprüchliche Erfahrungen haben, werde ich es sein Ich freue mich, sie zu hören und meinen Standpunkt zu aktualisieren.
Team, was halten Sie von einer Art "Community"-Abschnitt in der Dokumentation? Damit Benutzer wie ich seine Erfahrungen mit seiner Verwendung von pipenv teilen können, ohne unbedingt die volle Unterstützung des pipenv-Teams zu haben?
PS: Ich kann dies in ein spezielles Thema verschieben, wenn Sie diesen Thread nicht verschmutzen möchten
@vlcinsky (1) ist sehr einfach auszuführen - legen Sie Ihre Sperrdatei in Ihr Repository.
Ich denke, Sie meinen stattdessen: Es ist unmöglich, konkrete Ratschläge zu geben, wenn diese grundlegende Strategie nicht mehr ausreicht. Das ist sicher richtig, aber das liegt daran, dass das konkrete Problem wahrscheinlich von Fall zu Fall unterschiedlich ist.
Oder anders ausgedrückt: Die Lösung hängt davon ab, welche zusätzlichen Garantien Sie für Ihren CI-Workflow wünschen.
@gsemet weißt du was? Alle meine Python-Pakete, die in den letzten zwei Jahren erstellt wurden, basieren auf pbr
- es ist wirklich großartig. Und ich verfolge Ihre Versuche, Pipfile in pbr zu unterstützen, wann immer ich kann (einige Daumen hoch, Stimmen usw.).
In diesem Fall (Suche nach pipenv
Mustern und Antimustern für allgemeine Python-Bibliotheken) habe ich pbr
aus zwei Gründen absichtlich weggelassen:
pbr
aus anderen Gründen nicht (du hast sie erwähnt) und es würde die Diskussion wahrscheinlich ablenkenAuf der anderen Seite freue ich mich schon sehr auf ein Rezept von dir für PBR-Liebhaber. Ich werde es lesen.
@tsiq-oliverc du hast den Nagel getroffen: Lege deine Lockfile in dein Repo
Das ist genau das Problem, das mich motiviert hat, dieses Thema zu starten. Wenn Sie den Anfang dieses Problems noch einmal lesen, finden Sie eine Beschreibung einiger Fälle, in denen das Hinzufügen von Pipfile.lock
Ihre CI-Tests unterbrechen kann (entweder den Build-Lauf unterbrechen oder Probleme ausblenden, die sonst erkannt würden, oder falsche Abhängigkeiten installieren für gegebenen Kontext...).
Wenn Sie mir ein Repo zeigen, wo dies richtig gemacht wird (allgemeine Python-Bibliothek), würde ich mich freuen. Oder ich würde aufzeigen, welche Risiken es gibt oder welche Dinge unfertig sind.
Cool ! Ich pflege auch
@vlcinsky Richtig, also lass uns die spezifischen Probleme aufzählen und Lösungen dafür finden 😄 (Ich kenne keine hochwertige Bibliothek, die Pipenv verwendet, aber das liegt hauptsächlich daran, dass ich nicht nachgesehen habe.)
Soweit ich das beurteilen kann, sind dies die spezifischen Symptome in Ihrem ursprünglichen Beitrag:
pipenv install -e .
, richtig?@tsiq-oliverc Ich muss sagen, Ihre Kommentare haben mich inspiriert und ich weiß, dass sie zu einer höheren Reproduzierbarkeit der vorgeschlagenen Lösung beigetragen haben.
Folgendes bezieht sich auf Ihren Vorschlag, die Sperrdatei ( Pipfile.lock
) in das Repository zu legen, um die Wiederholbarkeit zu gewährleisten:
re Ausblenden defekter setup.py-Abhängigkeiten. . Die pipenv install -e .
folgen dem, was ich vorschlage, aber beachte, dass dies keine Verwendung von Pipfile.lock
, sondern eine Methode, um es (neu) zu erstellen. Wenn jemand Pipenv.lock
behält und damit virtualenv erstellt, bevor das Paket installiert wird, liegt das Problem vor.
re Abhängigkeiten sind wahrscheinlich für verschiedene Python-Versionen oder in einem anderen Betriebssystem ungültig . Es gibt viele Beispiele: doit
das für Python 2.7 installiert wurde, muss eine ältere Version sein, da die neuere Version die Unterstützung für Python 2.x eingestellt hat. watchdog
Abhängigkeit erfordert plattformabhängige Bibliotheken: inotify unter Linux, etwas anderes unter Windows, etwas anderes unter OSX. Mein ehemaliger Kunde sagte immer "Das wird nie passieren" und in 50% der Situation geschah dies innerhalb von 2 Wochen. Dies ist nicht die beste Vorgehensweise für CI-Skripte.
re Entwickler sind gezwungen zu aktualisieren .. Stellen Sie sich eine Open-Source-Bibliothek mit 15 Mitwirkenden vor. Es ist so leicht zu vergessen, Pipfile.lock
von einem Neuling oder müden Core-Entwickler zu regenerieren. ZB im maya
Paket wurde ich gebeten, Pipfile.lock
neu zu generieren, da eine neue Abhängigkeit zu setup.py
hinzugefügt wurde. War das nötig? Habe ich es richtig aktualisiert? Habe ich es für alle unterstützten Ausführungskontexte aktualisiert? Antworten sind nein, nicht sicher, nein. Wie auch immer, danke für Ihren Vorschlag (er hat mich zu der neben Ihrem Kommentar beschriebenen Lösung inspiriert).
re Im Wettbewerb mit tox : Tox ermöglicht die Erstellung mehrerer virtueller Umgebungen und die Automatisierung der darin ausgeführten Tests. Typisch tox.ini
definiert verschiedene virtuelle Umgebungen für Python 2.7, 3.4, 3.5, 3.6 und alle anderen, die Sie benötigen, und ermöglicht die Installation des Pakets dort und die Ausführung der Testsuite. Es ist ein etabliertes Powertool von ernsthaften Testern. pipenv
ist nicht das richtige Werkzeug für diesen Zweck, kann aber die Installation der benötigten Dinge stören. In gewisser Weise bin ich Ihrem Rat gefolgt und habe vorgeschlagen, nach Möglichkeit ein überlegenes Werkzeug (Tox) über pipenv
zu verwenden.
re Pipenv schlägt fehl. Das ist wirklich schade. Ich hatte einen CI-Test (tox-basiert), der auf localhost gut lief, aber wenn er über Travis ausgeführt wurde, schlug er aufgrund eines pipenv
Problems fehl. Wenn ich es jetzt verwenden möchte, hilft das Anheften nicht, bis der Fix veröffentlicht wird. Aber so geht es - ich warte.
Beachten Sie, dass einige Teile meines ursprünglichen Beitrags aktualisiert werden müssen, wie es scheint, die Verwendung von pipenv
in CI-Skripten hat ihren berechtigten Platz ("Versiegelung" der virtualenv-Konfiguration für eine mögliche spätere Verwendung).
@tsiq-oliverc Während mir Ihr Vorschlag, sowohl gegen das "bekannte Gut" als auch gegen die neuesten Versionen zu testen, anfangs gefiel, fällt es mir immer schwerer, den Aufwand zu rechtfertigen, je mehr ich darüber nachdenke. Ich denke, Sie sollten sich für das eine oder das andere entscheiden, nicht für beides.
Das einzige, was Sie gewinnen, ist, dass Sie sofort wissen, ob ein Fehler durch ein Abhängigkeitsupdate oder eine Codeänderung verursacht wurde. Aber Sie können dasselbe erreichen, indem Sie einfach separate Commits durchführen (wenn Sie gesperrte Abhängigkeiten manuell aktualisieren) oder versuchen, den Fehler mit der neuesten Sperrdatei eines erfolgreichen Builds zu reproduzieren (wenn Sie immer die neuesten Versionen verwenden). Und in eingeschränkten Umgebungen kann man sowieso nicht "einfach aktualisieren"...
@vlcinsky Während ich Ihrem allgemeinen Punkt zu den Unterschieden zwischen Umgebungen zustimme, klingt das Argument "eine Sperrdatei pro Konfiguration" für mich wie ein Strohmann. In der Praxis können Sie die Sperrdateien zumindest für einige Umgebungen freigeben.
Eine noch offene Frage, die noch niemand beantwortet hat, ist der Umgang mit dem Fall, in dem Sie beide in unterschiedlichen Umgebungen testen und Ihre Abhängigkeiten sperren müssen. Ich muss zugeben, dass ich nichts über tox
weiß, außer dass es existiert, aber es scheint, als ob zwischen tox
und pipenv
eine Art Klebstoff benötigt wird das löst dieses problem irgendwie.
@Moritz90
In Bezug auf zu viele Varianten von Pipfile.lock
die als Strohmann dienen (um andere von meinem Feld fernzuhalten):
Ich habe ein flask
Projekt genommen (da es sehr ausgereift ist) und Tox-Tests durchgeführt:
Hier sehen Sie eine Liste der getesteten Varianten (nur lokal unter Linux, multiplizieren Sie sie mit 3, da Windows und OSX die gleichen Tests durchführen, aber zu unterschiedlichen Umgebungen führen können).
Es gibt 16 verschiedene Testläufe auf einem Betriebssystem, 5 davon sind fehlgeschlagen, da ich sie nicht installiert habe (das ist in Ordnung), einer befasst sich mit dem Erstellen von Dokumenten (erfordert eine importable Bibliothek) und ein anderer deckt (was auch eine importierbare Bibliothek erfordert) ):
coverage-report: commands succeeded
docs-html: commands succeeded
py27-devel: commands succeeded
py27-lowest: commands succeeded
py27-simplejson: commands succeeded
py27: commands succeeded
py35: commands succeeded
py36-devel: commands succeeded
py36-lowest: commands succeeded
py36-simplejson: commands succeeded
py36: commands succeeded
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy-devel: InterpreterNotFound: pypy
ERROR: pypy-lowest: InterpreterNotFound: pypy
ERROR: pypy-simplejson: InterpreterNotFound: pypy
ERROR: pypy: InterpreterNotFound: pypy
Für jede der erstellten virtuellen Umgebungen habe ich eine requirements.txt
Datei von pip freeze > {venv_name}.txt
Dann berechnete Hashes für die Dateien, sortiert nach Hash-Werten, damit alle gleich gruppiert werden. Hier kommt der Strohmann:
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py35.txt
b231a4cc8f30e3fd1ca0bfb0397c4918f5ab5ec3e56575c15920809705eb815e py36.txt
cdf69aa2a87ffd0291ea65265a7714cc8c417805d613701af7b22c8ff2b5c0e4 py27-devel.txt
dfe27df6451f10a825f4a82dfe5bd58bd91c7e515240e1b102ffe46b4c358cdf py36-simplejson.txt
e48cd24ea944fc9d8472d989ef0094bf42eb55cc28d7b59ee00ddcbee66ea69f py36-lowest.txt
f8c745d16a20390873d146ccb50cf5689deb01aad6d157b77be203b407e6195d py36-devel.txt
053e107ac856bc8845a1c8095aff6737dfb5d7718b081432f7a67f2125dc87ef docs-html.txt
45b90aa0885182b883b16cb61091f754b2d889036c94eae0f49953aa6435ece5 py27-simplejson.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
564580dad87c793c207a7cc6692554133e21a65fd4dd6fc964e5f819f9ab249c py27.txt
8b8ff4633af0897652630903ba7155feee543a823e09ced63a14959b653a7340 py27-lowest.txt
Beängstigend, nicht wahr? Von allen Tests teilen nur zwei die gleichen eingefrorenen Abhängigkeiten.
Dies ist die Realität einer allgemeinen Python-Bibliothek mit einer guten Testsuite. Sie werden jetzt wahrscheinlich zugeben, dass dies etwas ganz anderes ist als die Python-Bibliothek, die in einer Unternehmensumgebung getestet wurde.
Überprüfen von jinja2
, was ein viel einfacheres Tier zu sein scheint:
coverage-report: commands succeeded
py26: commands succeeded
py27: commands succeeded
py33: commands succeeded
py35: commands succeeded
py36: commands succeeded
ERROR: docs-html: commands failed
ERROR: py34: InterpreterNotFound: python3.4
ERROR: pypy: InterpreterNotFound: pypy
Wenn ich Prüfsummen sehe, bin ich überrascht, dass sich py27.txt und py26.txt unterscheiden:
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py26.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py33.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py35.txt
047a880804009107999888a3198f319e5bbba2fa461b74cfdfdc81384499864e py36.txt
48bd0f6e66a6374a56b9c306e1c14217d224f9d42490328076993ebf490d61b5 coverage-report.txt
743ad9e4b59d19e97284e9a5be7839e39e5c46f0b9653c39ef8ca89c7b0bc417 py27.txt
@vlcinsky Das ist in der Tat beängstigend. Ich frage mich, ob Flask ein Sonderfall ist oder ob das tatsächlich die Norm ist, aber Sie haben mir definitiv das Gegenteil bewiesen.
Ich hoffe jetzt, dass unsere Python-Bibliothek nicht eines Tages unter dem gleichen Problem leiden wird und dass die Unterschiede dort besser überschaubar sind.
@ Moritz90 Ihre interne Bibliothek bedient ein ganz anderes Publikum, sodass Sie es sich leisten können, den Ausführungskontext viel enger zu halten.
Allgemeine Python-Bibliotheken sind oft flexibel und konfigurierbar, zB erlaubt Flask die Installation und Nutzung alternativer Json-Parser, was durch einen separaten Testlauf abgedeckt wird.
Man kann viel über Testen und Toxen von Flasks tox.ini
lernen
Die niedrigsten Testvarianten achten darauf, gegen die älteste Abhängigkeitsversion zu testen.
devel testet gegen die Entwicklungsversion der Kernabhängigkeiten.
Ich würde sagen, Flask ist auf der höheren Komplexitätsebene und weist eine sorgfältige Testsuite auf.
Die tox.ini von Pyramid zeigt eine ähnliche Anzahl von Umgebungen (sie zielen auch auf eine 100%ige Codeabdeckung ab).
mayas tox.ini ist sehr frisch (2 Tage) und einfach, auch hier gibt es 4 verschiedene Umgebungen und py27 unterscheidet sich in den eingefrorenen Anforderungen von py35 und py36.
@Moritz90
Zum Kleber zwischen Pipenv und Tox
pipenv --man
zeigt einige Anweisungen, wie man pipenv
innerhalb von tox.ini
Befehlen verwendettox.ini
Datei pipenv
einschließt.
pipenv
hat eine großartige Funktion, die, wenn sie in einer bereits aktivierten virtuellen Umgebung ausgeführt wird (was bei toxbasierten Tests der Fall ist), in einer bestimmten virtuellen Umgebung installiert wird. Das ist wirklich schön.
Da wir wahrscheinlich Pipfile.lock
generieren müssen, müssen einige zusätzliche Anstrengungen unternommen werden, um es zu bekommen und an die richtige Stelle zu verschieben (ag in .tox/py36/Pipfile.lock
, um ein Überschreiben durch den folgenden Test zu verhindern. Dies ist möglich, aber mit einigen Vereinfachungen wäre willkommen.Vielleicht würde es ein Trick mit der Umgebungsvariablen für den Standort von Pipfile
noch einfacher machen.
@vlcinsky
pipenv install -e .
einmal aus, sodass setup.py jetzt über Ihre Sperrdatei verfolgt wird. Führen Sie dann pipenv install
wenn Sie setup.py neue Pakete hinzufügen.pipenv --deploy
entwickelt, um dies abzufangen . Führen Sie es in Ihrem CI aus!update-all-lockfiles.sh
lokal erstellen und pipenv --deploy
auf Ihrem CI ausführen, um Fehler abzufangen.@ Moritz90 -
Allgemeiner gesagt wäre es gut, sicherzustellen, dass sich dieser "Vorschlag" auf die Dinge konzentriert, die eigentlich schwierige Probleme sind (meiner Ansicht nach (A) mehrere Umgebungen bedienen, (B) Änderungen in Upstream-Abhängigkeiten abfangen wollen). Es sollte nicht auf vorübergehenden Dingen (Bugs in Pipenv) oder möglichen Missverständnissen bezüglich der Verwendung des Tools basieren.
Aber selbst für diese "harten" Probleme sollte das Framing so aussehen: "In einigen komplexen Randfällen kann es sein, dass ein grundlegender Pipenv-Workflow nicht ausreicht, also sind hier einige Dinge zu beachten". IMO, es sollte nicht als Standardansatz bezeichnet werden (da die meisten Leute diese Bedenken nicht haben).
Das von @vlcinsky bereitgestellte Dokumentationsbeispiel würde einfacher und weniger verwirrend, wenn Pipenv/Pipfile die Behandlung von lib-dependencies
, app-dependencies
und dev-dependencies
zulassen würde. Dokumente könnten etwa so aussehen:
Verwenden Sie die Option lib-dependencies
wenn es sich bei Ihrem Paket um eine gemeinsam genutzte Bibliothek handelt. Beispiel Pipfile
:
[lib-dependencies]
some-lib=="*"
another-lib=="*"
yet-another-one==">=1.0"
[dev-dependencies]
some-dev-tool=="1.1"
Bei Shared Libraries ist es wichtig, die Versionsbereiche unter [lib-dependencies]
so breit wie möglich zu halten, um Versionskonflikte auf dem Consumer-System zu vermeiden.
Wenn Ihr Paket eine Anwendung ist (die von pipenv auf dem Zielsystem installiert werden soll), die genaue Abhängigkeitsversionen erfordert, sollten Sie die Option [app-dependencies]
. Beispiel Pipfile
:
[app-dependencies]
some-lib=="1.0.12"
another-lib=="1.*"
yet-another-one=="2.0"
[dev-dependencies]
some-dev-tool=="1.1"
/Enddokument-Beispiel
Ein anderer Ansatz könnte ein Pipfile.lib
und ein Pipfile.app
.
Ich denke, so etwas würde die Notwendigkeit eines Teils von Anti-Pattern-Abschnitten und Tools von Drittanbietern überflüssig machen, um die Lücke zu füllen.
Pipenv-Packaging-Tool zu nennen, ist irreführend, wenn man erwartet, dass es Python-Bibliotheken erstellt oder stark an deren Erstellung beteiligt ist.
Ich denke, das ist ein echtes Problem, das zu viel Verwirrung führt. Vor allem bei Leuten, die es gewohnt sind, Manager in anderen Programmiersprachen (zB JS, Rust, Elm) zu packen. Es dauerte mehrere Monate und ich habe gelegentlich Github-Probleme gelesen, bis mir klar wurde, dass ich Pipenv und setup.py falsch verwendet habe.
@luxus
Ihr [lib-dependencies]
oder Pipfile.lib
ist das, was wir heute in Pipfile
(als abstrakte Abhängigkeiten - so breit wie möglich).
Ihre [app-dependencies]
oder Pipfile.app
haben wir in Pipfile.lock
(als spezifische Abhängigkeiten).
pipenv
und seine Dateien können in zwei verschiedenen Situationen verwendet werden - beim Entwickeln einer Bibliothek oder beim Vorbereiten einer Anwendungsbereitstellung, aber wahrscheinlich nicht für beides gleichzeitig. Aus diesem Grund sehe ich keine triftigen Gründe dafür, zusätzliche Abschnitte in Pipenv
hinzuzufügen. Es liegt in der Verantwortung der Entwickler zu wissen, welchen Zweck die Pipfile
erfüllen werden.
Ich denke, das ist ein echtes Problem, das zu viel Verwirrung führt. Vor allem bei Leuten, die es gewohnt sind, Manager in anderen Programmiersprachen (zB JS, Rust, Elm) zu packen. Es dauerte mehrere Monate und ich habe gelegentlich Github-Probleme gelesen, bis mir klar wurde, dass ich Pipenv und setup.py falsch verwendet habe.
Einverstanden. Die dreiteilige Lösung ist auch eine sehr interessante Lösung, die ich noch nie in Betracht gezogen habe, und sie scheint richtig und (überraschend!) einfach zu sein.
Da ich selbst einen Python-Hintergrund habe, hatte ich immer das Gefühl, dass Nodes package.json es falsch macht (Rust ist besser, weil es einen Compiler und einen Linker hat und dies zu einem späteren Zeitpunkt beheben kann). App- und lib-Abhängigkeiten auf die gleiche Weise zu behandeln, funktioniert für eine Skriptsprache wie Python zumindest im abstrakten Sinne einfach nicht – dh es könnte für Sie funktionieren, aber ein generisches Tool wie Pipenv kann dies nicht, weil es so sein muss generisch.
Obwohl ich die dreiteilige Lösung im Konzept mag, ist sie immer noch eine ziemlich inkompatible Änderung des bestehenden Ökosystems. Es gibt bereits setup.py, setup.cfg und (möglicherweise) pyproject.toml, die diesen Platz füllen. Wenn Pipenv (genauer gesagt Pipfile) in den Space einziehen möchte, muss es sich mit verwandten Projekten wie pip (die Bibliotheksunterstützung sollte idealerweise direkt von ihm unterstützt werden) und flit konsolidieren.
Wie ich in anderen Fragen zur Handhabung von lib/app-Abhängigkeiten erwähnt habe, muss diese Diskussion an pypa-dev (die Mailingliste) und/oder den PEP-Prozess eskaliert werden, damit sie von anderen Parteien und relevanten Personen besser gehört werden kann, bevor Pipenv (Pipfile) kann sich in alle Richtungen bewegen.
@vlcinsky
Ihre [lib-dependencies] oder Pipfile.lib ist das, was wir heute in Pipfile haben (als abstrakte Abhängigkeiten - so breit wie möglich).
Sorry, wenn das nicht klar war. Meine lib-dependencies
sollen das sein, was die Leute derzeit in setup.py
/ install_requires
. Vielleicht wäre pypi-dependencies
ein besserer Name für das, was ich meinte.
@uranusjr
Es gibt bereits setup.py, setup.cfg und (möglicherweise) pyproject.toml, die diesen Platz füllen.
Pipenv (das Befehlszeilentool) könnte setup.py
Schnittstelle verwenden. Nur der Abhängigkeitsabschnitt von setup.py
müsste nach Pipfile verschoben werden. Zumindest in meiner Vorstellung :)
Wie ich in anderen Fragen zur Handhabung von lib/app-Abhängigkeiten erwähnt habe, muss diese Diskussion an pypa-dev (die Mailingliste) und/oder den PEP-Prozess eskaliert werden, damit sie von anderen Parteien und relevanten Personen besser gehört werden kann, bevor Pipenv (Pipfile) kann sich in alle Richtungen bewegen.
Ok, sorry für die Mühe ;) Wenn ich etwas Zeit finde, schreibe ich etwas für die Mailingliste.
Im Rahmen dieses Vorschlags würde ich jedoch vorschlagen, sich auf die derzeit möglichen Best Practices zu konzentrieren, anstatt in den Kaninchenbau zu gehen, einen neuen Workflow für die gesamte Python-Packaging-Community zu erarbeiten. Es wäre produktiver, innerhalb der aktuellen Einschränkungen eine Best Practice vorzuschlagen und dann die Diskussion über Verbesserungen zu beginnen.
@uranusjr - Ich komme aus einem "kompilierten" Hintergrund, also bin ich neugierig, warum das so ist?
Die gleiche Behandlung von App- und Lib-Abhängigkeiten funktioniert für eine Skriptsprache wie Python einfach nicht
@tsiq-oliverc Da die Best Practice der App erfordert, dass Sie Ihre Abhängigkeiten anheften, würden Bibliotheken auch ihre anheften, wenn sie dieselbe Quelle von Anforderungsdateien verwenden. Dies würde zu Problemen bei der Abhängigkeitsauflösung führen.
Sagen wir, meine App hat zwei Abhängigkeiten A und B, beide hängen von C ab, aber A-Pins v1, während B-Pins v2. Kompilierte Sprachen ermöglichen es der Toolchain, dies zur Kompilierzeit zu erkennen und auf viele Arten zu lösen. Rust macht dies zum Beispiel während der Linkzeit – Die ausführbare Enddatei würde zwei Kopien von C (v1 und v2) enthalten, wobei A und B jeweils mit ihnen verknüpft sind. Im C++-Land würde dies mit dynamischen Bibliotheken gelöst werden; die Symbolsuche erfolgt noch später (zur Laufzeit), aber die Idee ist dieselbe – der Compiler weiß, was Sie brauchen (von der verwendeten Schnittstelle) und kann entsprechend handeln.
Skriptsprachen können dies nicht, weil sie nicht wissen, was Sie wirklich tun möchten, bis sie den Anruf tatsächlich erreichen. Node umgeht dies, indem es immer davon ausgeht, dass die Abhängigkeiten inkompatibel sind (A und B erhalten immer ihr eigenes C, auch wenn die beiden Kopien identisch sind), aber das führt zu einer neuen Klasse von Problemen und führt zu unangenehmen Hacks wie Peer-Abhängigkeiten, die jeder (hoffe ich?) stimmt zu, sind schrecklich. Python möchte wahrscheinlich nicht dorthin gehen (es kann sowieso nicht, da dies wahrscheinlich alle vorhandenen Python-Installationen zerstören würde).
Eine andere Möglichkeit, dies zu umgehen, besteht darin, in den Paketierungstools etwas Cleveres zu tun, das die Abhängigkeitsversion „auflöst“. Bundler (von Ruby) tut dies, indem er den Leuten empfiehlt, die Lock-Datei nicht in das Gem einzubinden, damit Bundler die ungepinnten Versionen in Gemfile anstelle der gepinnten Versionen in Gemfile.lock verwenden kann. Aber die Leute neigen dazu, Ratschläge zu ignorieren und zu tun, was sie wollen, so dass Sie immer noch überall gepinnte Versionen bekommen.
Ich war wohl etwas zu stark um zu sagen, dass es einfach nicht geht . Aber zumindest sind alle bisherigen Versuche gescheitert, und viele von denen, die es versucht haben, sind sehr schlaue Leute, viel klüger als ich. Ich persönlich glaube nicht, dass dies möglich ist, und ich würde weiterhin so denken, bis ich den sehr brillanten Vorschlag sehe, der dies tatsächlich tut.
@tsiq-oliverc Pieter Hintjens schrieb irgendwo ein Konzept von "Kommentare sind willkommen in Form von Pull-Requests"
Ich mag das, weil es den Fokus von philosophischen Ratschlägen auf wirklich greifbare und praktische Dinge verschiebt. Und es begrenzt auch die Anzahl der Kommentare, da ein Kommentator oft auf dem Weg erfährt, dass die Idee im realen Gebrauch unvollständig oder irgendwie kaputt ist.
Ich habe Sie nach einem Beispiel für eine Python-Bibliothek gefragt, in der pipenv
ordnungsgemäß verwendet (oder zumindest verwendet) wird und Sie keine bereitgestellt haben.
Sie kommentieren die Qualitäten von tox
, geben aber zu, dass Sie damit nicht vertraut sind, und wiederholen immer noch etwas über bewährte Verfahren in der Welt der Python-Paketentwicklung.
Sie sagen, Flask
ist möglicherweise ein Sonderfall. Also durchsuchte ich Github nach Python-Projekten mit dem Wort "Bibliothek", sortiert nach der Anzahl der Forks (da es wahrscheinlich widerspiegelt, wie viele Leute damit arbeiten), ignorierte alle "kuratierten Listen von etwas" und zählte die Anzahl der Umgebungen für eine Betriebssystem (normalerweise Linux):
Die tatsächliche Anzahl der Umgebungen, in denen Tests ausgeführt werden sollen, ist meistens 2 (+Windows) oder 3 (+OSX) höher.
tox
wird in 2 von 3 Projekten verwendet (ich vergleiche es nicht mit Travis oder Appveyor, da sie eine andere Testebene durchführen).
Die Anzahl der zu testenden Umgebungen ist ziemlich hoch, Flask ist definitiv nicht die wildeste.
Die Anzahl der Umgebungen, für die feste Abhängigkeiten definiert werden müssen, ist wirklich nicht manuell zu verwalten.
Das einfache Ablegen von Pipfile.lock
in ein Repository ist ziemlich einfach, aber es bringt keine magische Verbesserung (wenn ja, zeigen Sie mir ein reales Szenario, wann es die Situation verbessern wird).
Vielleicht kennen Sie die goldene Regel aus der "kompilierten" Welt und denken, dass Determinismus (oder Wiederholbarkeit) auch für Python ein Muss ist. Wie Sie sehen, leben wirklich viele Python-Projekte ziemlich gut ohne es, daher kann die goldene Regel hier nicht so streng gelten.
Ich würde mich freuen, wenn wir pipenv
für Python-Bibliotheken finden, die die Situation verbessern. Und ich möchte eine Nutzung verhindern, die die Gesamtqualität beeinträchtigen würde.
Um dieses Ziel zu erreichen, gehe ich vor, über Fragen zu iterieren:
@luxus
Sorry, wenn das nicht klar war. Meine lib-Abhängigkeiten sollen das sein, was die Leute derzeit in setup.py / install_requires eingeben. Vielleicht wäre pypi-dependencies ein besserer Name für das, was ich meinte.
Siehe pbr
Diskussion in dieser Ausgabe. Es ist das Bestreben, Bibliotheksabhängigkeiten von Pipfile zu unterstützen.
Ich denke, dass ein Pipfile
nicht für zwei Zwecke (Lib und App) verwendet werden sollte, diese Dinge müssen separat gemacht werden. Wenn Sie der Meinung sind, dass es wirklich benötigt wird, könnten Sie den Zweck eines Projekts beschreiben, in dem es verwendet wird? Normalerweise versuche ich, Bibliotheksentwicklungs- und Bereitstellungsprojekte getrennt zu halten, da sie im Laufe der Zeit recht unterschiedlich verwendet werden.
@vlcinsky Ich bin mir nicht wirklich sicher, wohin Sie das bringen möchten (ich bin mir nicht sicher, nach welcher Art von PR Sie fragen!), also werde ich mich vorerst aus diesem Gespräch verbeugen.
Um den TL;DR meiner Position neu zu formulieren:
@uranusjr Verstanden . Obwohl ich glaube, dass es hier nichts sprachspezifisches gibt, haben sich verschiedene Communities einfach auf unterschiedliche Heuristiken für den Umgang mit einem Problem ohne generische Lösung geeinigt - wenn Sie Versionskonflikte haben, haben Sie ein Problem.
Maven/Java (zum Beispiel) zwingt Sie dazu, zur Build-Zeit darüber nachzudenken. Der NPM-Weg bedeutet, dass Sie Laufzeitprobleme haben, wenn die nicht übereinstimmenden Versionen eine Schnittstelle überschreiten. Laufzeitauflösung (zB Python, dynamische Bibliotheken) bedeutet, dass eine abhängige Datei abstürzen kann/etc. wenn die Abhängigkeitsversion nicht den Erwartungen entspricht.
@vlcinsky
Siehe pbr-Diskussion in dieser Ausgabe. Es ist das Bestreben, Bibliotheksabhängigkeiten von Pipfile zu unterstützen.
pbr scheint nett und alles, aber es fällt in die Kategorie, die ich damit ansprechen wollte:
Ich denke, so etwas würde die Notwendigkeit eines Teils von Anti-Pattern-Abschnitten und Tools von Drittanbietern überflüssig machen, um die Lücke zu füllen.
Ich denke, solche Tools sollten von vornherein nicht notwendig sein.
Wenn Sie der Meinung sind, dass es wirklich benötigt wird, könnten Sie den Zweck eines Projekts beschreiben, in dem es verwendet wird? Normalerweise versuche ich, Bibliotheksentwicklungs- und Bereitstellungsprojekte getrennt zu halten, da sie im Laufe der Zeit recht unterschiedlich verwendet werden.
Wenn es um Pypi-Pakete geht, habe ich Pipenv verwendet, um Entwicklungsabhängigkeiten zu behandeln, Pipfile
um Entwicklungsabhängigkeiten zu beschreiben, setup.py
um lib-Abhängigkeiten mit install_requires
und setuptools
in setup.py
um mein Paket mit pipenv run python setup.py bdist_wheel upload
. Das halte ich für kompliziert.
In anderen modernen Sprachen muss ich ein Befehlszeilentool (Paketmanager) plus ein Abhängigkeitsdateiformat lernen. Die Dokumentation ist an einem Ort und einfacher zu verfolgen und ein Neuling wird all dies in ein paar Stunden klären. Es geht um npm init
, npm install foo --dev
, npm publish
. Pipenv/Pipfile kann das meiste schon, wenn es alles könnte, gäbe es solche Probleme nicht.
Ich wiederhole meine Forderung nach einer Art "Community"-Sektion/Wiki für diese Diskussion. Es gibt mehrere "Muster", die legitim sind, und einige von uns möchten sie vielleicht teilen, "Python-Bibliotheken zu erstellen", einige wie ich mit pbr und andere haben möglicherweise ein sehr gutes Muster. Aber eine Seite im pipenv-Dokument, ich bin mir nicht sicher, ob es eine gute Idee ist.
PS: Um die Migration auf die neue pypi vorzubereiten, sollten Sie twine verwenden und nicht python setup.py hochladen. Die Verwendung von "Upload" sollte als Antimuster betrachtet werden.
Vielleicht kann pipenv "veröffentlichen" Befehle wachsen lassen?
@feluxe Vielleicht möchten Sie einen Blick auf Poesie werfen. Ich stolpere gerade darüber und es scheint, dass es das ist, was Sie suchen.
Es tut, was pipenv
tut und mehr und es scheint, dass sie es besser machen, insbesondere in Bezug auf das Abhängigkeitsmanagement (zumindest geben sie so vor). Es übernimmt Abhängigkeitsmanagement, Paketierung und Veröffentlichung eines einzigen Tools poetry
.
Ich frage mich, ob pipenv
und poetry
Anstrengungen unternehmen könnten, um Python endlich einen echten Paketmanager zu geben.
Ich möchte mich noch einmal wiederholen, bevor diese Diskussion zu weit geht. Pipenv kann nicht einfach einen publish
Befehl erstellen oder irgendetwas tun, das versucht, die Verpackungsaufgabe zu übernehmen. Dies würde das Ökosystem nur noch mehr fragmentieren, da dies nicht jeder auf diese Weise tut, und da App- und Lib-Abhängigkeiten theoretisch unterschiedlich sind, können Sie niemandem sagen, dass er sie wieder zusammenführen soll, sobald die Unterscheidung in seinem Workflow getroffen wurde.
Es mag den Anschein haben, dass fast jeder an dieser Zusammenführung teilnimmt, aber die Wahrheit ist, dass sich viel mehr Leute nicht an dieser Diskussion beteiligen, weil die Dinge für sie funktionieren und sie etwas anderes tun. Ich habe es wiederholt gesagt: Diskussionen über die Verbesserung des Designs von Toolchains und Dateiformaten sollten an einer höheren Stelle in der Python-Pakethierarchie stattfinden, damit sie mehr Kontakt mit Leuten erhält, die grundlegendere Dinge entwerfen, auf die sich Pipenv stützt. Bitte nehmen Sie die Diskussion dort auf. Es hat keinen Sinn, es hier vorzuschlagen, da Pipenv nicht in der Lage ist, es zu ändern.
Ich habe es wiederholt gesagt: Die Diskussion über die Verbesserung des Designs von Toolchains und Dateiformaten sollte an einer höheren Stelle in der Python-Pakethierarchie stattfinden, damit sie mehr Menschen ausgesetzt ist, die grundlegendere Dinge entwerfen, auf die sich Pipenv stützt.
Ich stimme zu, dass die Diskussion über diesen Fehler jetzt, da das Paketieren und Veröffentlichen auftaucht, außer Kontrolle gerät (dieser Fehler betrifft nur das Abhängigkeitsmanagement!), aber könnten Sie uns bitte an die richtige Stelle für diese Diskussion verweisen? Die Leute haben es hier, weil pipenv als dringend benötigter Schritt in die richtige Richtung angesehen wird, nicht weil sie den pipenv-Maintainern zusätzliche Verantwortung auferlegen wollen.
Edit : Entschuldigung, ich muss den Beitrag verpasst haben, in dem du genau das getan hast, als du die neuen Kommentare zum ersten Mal gelesen hast.
Im Rahmen dieses Vorschlags würde ich jedoch vorschlagen, sich auf die derzeit möglichen Best Practices zu konzentrieren, anstatt in den Kaninchenbau zu gehen, einen neuen Workflow für die gesamte Python-Packaging-Community zu erarbeiten. Es wäre produktiver, innerhalb der aktuellen Einschränkungen eine Best Practice vorzuschlagen und dann die Diskussion über Verbesserungen zu beginnen.
Dem stimme ich sehr zu. Wir sollten zuerst herausfinden , was die beste Workflow für die Bibliothek Maintainer jetzt ist , bevor wir mit großen Plänen kommen. Konzentrieren wir uns also noch einmal darauf, wie wir es am Anfang dieses Threads getan haben. Ich glaube, wir sind noch nicht zu einem Ergebnis gekommen.
Zurück zum Thema: Zitat von @uranusjr , warum Abhängigkeiten in einer anderen Datei für Bibliotheken definiert werden sollten:
Eine andere Möglichkeit, dies zu umgehen, besteht darin, in den Paketierungstools etwas Cleveres zu tun, das die Abhängigkeitsversion „auflöst“. Bundler (von Ruby) tut dies, indem er den Leuten empfiehlt, die Lock-Datei nicht in das Gem einzubinden, damit Bundler die ungepinnten Versionen in Gemfile anstelle der gepinnten Versionen in Gemfile.lock verwenden kann. Aber die Leute neigen dazu, Ratschläge zu ignorieren und zu tun, was sie wollen, so dass Sie immer noch überall gepinnte Versionen bekommen.
Ich war wohl ein bisschen zu stark, um zu sagen, dass es einfach nicht funktionieren wird. Aber zumindest sind alle bisherigen Versuche gescheitert
Ich verstehe immer noch nicht, warum die offizielle Empfehlung für Bibliotheken vorerst nicht sein kann, pipenv
für ihre CI-Builds zu verwenden, aber Pipfile.lock
außerhalb der Quellcodeverwaltung zu lassen. Da pipenv
, wie einige Leute darauf hingewiesen haben, derzeit nichts mit dem Verpackungsprozess zu tun hat, sollten wir nicht auf das oben beschriebene Problem stoßen.
Und ich verstehe auch nicht, warum dies ein Argument gegen die Definition Ihrer abstrakten Abhängigkeiten in derselben Datei ist, die Anwendungen verwenden, um ihre abstrakten Abhängigkeiten zu definieren. Es ist in Ordnung, wenn pipenv
keine ausgeklügelte Lösung für die Integration von Pipfile
mit setup.py
implementieren möchte, aber ich verstehe nicht, warum das im Allgemeinen eine schlechte Idee ist.
@vlcinsky
Ich denke, dass ein Pipfile nicht für zwei Zwecke (Lib und App) verwendet werden sollte, diese Dinge müssen getrennt durchgeführt werden.
Siehe meinen obigen Beitrag. Könnten Sie bitte erläutern, warum Sie das denken? Grundsätzlich kann ich keinen Nachteil erkennen. Im Moment ist es vielleicht eine schlechte Idee, ein Pipfile
, da Sie dann die Abhängigkeiten in zwei verschiedenen Dateien auf die gleiche Weise definieren müssen, aber ich habe noch kein Argument gesehen, das erklärt, warum Es wäre eine schlechte Idee, Pipfile
für Abhängigkeitsdeklarationen im Allgemeinen zu verwenden.
Beachten Sie, dass ich bereits zugestimmt habe, dass Pipfile.lock
nicht in der Quellcodeverwaltung für Bibliotheken sein sollte, es sei denn, Sie befinden sich in der gleichen Situation wie ich.
Bearbeiten : Wenn sich herausstellt, dass pipenv
selbst den Unterschied kennen muss, können Sie einfach etwas wie das Feld crate-type
cargo einführen, bevor Sie mit der Einführung von app-dependencies
und lib-dependencies
- das klingt zu kompliziert.
@ Moritz90 Mehrere Mailinglisten von Python wären gute Orte, um diese Diskussion zu führen.
pypa-dev ist am besten umgebende Ökosystem. Ich würde wahrscheinlich hier anfangen, wenn ich eine ähnliche Diskussion posten würde.
python-ideas ist ein Ort, um Ideen zu diskutieren, und hat eine ziemlich hohe Sichtbarkeit für die gesamte Python-Community. Es wäre auch ein guter Ausgangspunkt, wenn Sie dies auf die PEP-Ebene bringen möchten (ich denke, Sie würden es irgendwann tun).
@tsiq-oliverc
Mit PR meine ich: Zeigen Sie ein Beispiel, das Ihr Konzept tragfähig macht.
Also nimm eine vorhandene Bibliothek, fork sie, wende deine (1) an - du sagst, es soll einfach sein mit pipenv
und zeig es mir. Ich habe mich ziemlich bemüht und habe Schwierigkeiten.
Wenn Ihr (2) bedeutet, dass „jemand anderes die Arbeit machen muss“, existiert Ihre PR nicht.
In (3) sprechen Sie von einer "kleinen Teilmenge von Fällen", ohne eine reelle Zahl anzugeben. Werden alle Top-Bibliotheken, die ich in Bezug auf die Anzahl der virtuellen Umgebungen beschrieben habe, als "kleine Teilmenge" betrachtet?
Um diese Diskussion abzuschließen, habe ich eine kurze Zusammenfassung der während der Diskussion gefundenen Ergebnisse erstellt.
pipenv
(Anti-)Muster für Python-Bibliotheken und -AnwendungenIch habe den Fokus etwas geändert: Es geht nicht nur um (allgemeine) Python-Bibliotheken, sondern auch um Anwendungen, da es ziemlich billig war, sie einzubinden und die Unterschiede gut demonstrieren.
Ich habe absichtlich alles ausgeschlossen, was Änderungen an bestehenden Tools vorschlägt, wie pipenv
, tox
usw.
pipenv
und was nichtPipfile.lock
zu definieren und anzuwenden.Das Produkt (Python-Software) ist entweder bereit, in einem anderen Produkt (also einer Bibliothek) verwendet zu werden, oder es ist die endgültige Anwendung, die ausgeführt werden kann.
Persönlich denke ich, dass sogar "Enterprise-Bibliotheken" in die Bibliothekskategorie fallen (es gelten die gleichen Regeln, nur die Anzahl der Ausführungskontexte ist kleiner).
pipenv install <package>
also "das Paket ins Spiel bringen (Versionen für andere Bibliotheken auflösen)"pipenv sync
also "konkrete Abhängigkeiten anwenden"konkrete Abhängigkeiten: muss Versionen anheften, idealerweise mit Hashes von verwendeten Bibliotheken
pipenv
Artefakte:Pipfile
: abstrakte Abhängigkeiten
Pipfile.lock
: konkrete (gesperrte) Abhängigkeiten"tox
oder eine ähnliche Testsoftwarepipenv
und konkrete Abhängigkeiten (kann für Bibliotheken in Ordnung sein)Pipfile
im RepositoryPipfile.lock
erstellt von pipenv install -e .
Pipfile.lock
dokumentiert (versiegelt) die Umgebung und ermöglicht die spätere Reproduktion von virtualenv zur Analyse von Problemen.Modus: "Eiszeit"
setup.py
install_requires
) ändern oder das abhängige Paket auf pypi aktualisiert wird, regeneriere Pipfile.lock
um pipenv install -e .
pipenv sync Pipfile.lock
Pipfile.lock
erstellt werdenmanuell vom Entwickler (kann für Anwendungen funktionieren)
Anwendung: Determinismus (im ausgewählten Ausführungskontext genauso ausgeführt)
public pypi (geringer Determinismus, Pakete werden jederzeit aktualisiert)
Pipfile.lock
): totaler DeterminismusPipfile.lock
:Anwendung in der Produktion bereitstellen
pbr
Bibliothek ermöglicht die Definition abstrakter Bibliotheksabhängigkeiten über requirements.txt
. Update-Lesung Pipfile
ist unterwegs.
poetry
Paket versucht etwas Ähnliches wie pyenv
"drop lockfile into repo" und Sie erhalten deterministische Builds:
Pipfile.lock
. Im Ernst: flask
zeigt auf seinen 11 verschiedenen virtuellen Umgebungen (auf einem Betriebssystem) 10 verschiedene gesperrte Abhängigkeiten. Wer wird sie erstellen und verpflichten?Pipfile.lock
(aber generiert durch CI-Skript) erhalten können, um die virtuelle Umgebung an anderer Stelle zu regenerieren.Pipfile.lock
im Bibliotheks-Repositorysetup.py
verbergen.Pipfile
im Bibliotheks-Repositorysetup.py
), kann es defekte setup.py
Abhängigkeitsdeklarationen verbergen.Pipfile
von pipenv install -e .
oder pipenv install -e .[tests]
wenn Sie auch Testabhängigkeiten benötigen und diese als "Tests"-Extras in den setup.py
deklariert sindpipenv install <something>
zu CI-Skriptenpipenv
).Python-Bibliotheken (insbesondere allgemeine) weisen eine unerwartet hohe Anzahl von Ausführungskontexten auf. Der Grund dafür ist, dass bei Bibliotheken nachgewiesene Flexibilität unter unterschiedlichen Bedingungen das Ziel ist. Die Flexibilität scheint wichtiger als deterministische Builds. Für Leute, die aus der "Compile"-Welt kommen, kann sich dies wie ein sehr schlechtes Antimuster anfühlen. Tatsache ist, dass die meisten (möglicherweise alle) Python-Bibliotheken keine deterministischen Builds bieten (wenn Sie einige kennen, lassen Sie es mich wissen) und Python läuft immer noch sehr gut. Die Gründe, warum Python-Anwendungen noch am Leben sind, könnten sein: Python als Skriptsprache unterscheidet sich von der kompilierten Welt. Der andere Grund könnte sein, dass der Determinismus einen Schritt später aufgelöst werden kann (sollte), sobald eine Anwendung (aus einer Menge von Bibliotheken erstellt) die (natürliche und berechtigte) Forderung nach Determinismus auflösen soll.
Bei Anwendungen ist die Situation genau umgekehrt und hier ist der Determinismus mit Werkzeugen wie pipenv
sehr einfach zu erreichen.
Was macht man als nächstes?
Danke an alle für die sehr anregende Diskussion - ich fühle mich als Botschaft "Ich bin total verloren in diesem Thema" dreimal umgestaltet - was bedeutet natürlich, dass wir besser geworden sind.
@vlcinsky poetry
hat nichts mit pyenv
zu tun. Es ist ähnlich wie pipenv
(aber mit einer viel besseren Implementierung in Bezug auf die Verwaltung von Bibliotheken und Anwendungen, IMO), aber mit dem Paketierungs- und Veröffentlichungsteil.
Sie haben eine pyproject.toml
Datei, die Ihr Projekt und seine Abhängigkeiten (abstrakte Abhängigkeiten) definiert, und eine pyproject.lock
pyproject.toml
Datei, die die angehefteten Abhängigkeiten beschreibt und für jede Python-Version und -Plattform angeheftet ist die pyproject.toml
file angegeben hat, um nur eine deterministische Sperrdatei zu haben, um die Probleme zu vermeiden, denen pipenv
gegenübersteht. Nur bei der Installation prüft poetry
, welche Pakete installiert werden sollen, indem es sie mit der Umgebung abgleicht.
Und wenn es Ihre Bibliothek paketiert, verwendet es die abstrakten Abhängigkeiten (und nicht die angehefteten), damit Sie die Flexibilität bei der Verteilung Ihres Pakets (zum Beispiel über PyPI) behalten.
Dies hat den Vorteil, dass abstrakte Abhängigkeiten für Bibliotheken und die Sperrdatei für Anwendungen verwendet werden. Dies ist das Beste aus beiden Welten.
@zface Poesie, die keine
Im Wesentlichen investieren wir viel Zeit und Mühe in die Belastbarkeit, damit kleine Projekte, die hohe Ansprüche stellen, nicht so viel Aufwand betreiben müssen, weil die Leute nicht auf Grenzfälle stoßen. Wenn Sie wirklich glauben, dass ein anderes Tool Ihnen das Beste aus allen Welten bietet, dann empfehle ich Ihnen, es zu verwenden – pipenv selbst wird in naher Zukunft nicht die Verpackung für Sie übernehmen, wenn überhaupt.
@techalchemy Ich verkaufe wirklich nichts, ich orientiere mich nur an Ideen, die in pipenv
verwendet werden könnten.
Und poetry
fixiert Abhängigkeiten in pyproject.lock
, genau wie pipenv
in Pipfile.lock
. Sie haben also eine Reproduktion, wie es pipenv
bietet. Wenn Sie eine Sperrdatei haben, wird sie verwendet und die angeheftete Abhängigkeit installiert, und wenn ich mich nicht irre, ist es auch das, was pipenv
tut.
Abstrakte Abhängigkeiten werden nur verwendet, wenn das Projekt für die Verteilung gepackt wird (also im Grunde genommen für Bibliotheken), da Sie in diesem Fall keine angehefteten Abhängigkeiten möchten.
@vlcinsky Es gibt noch ein paar Punkte, die aussortiert, korrigiert oder erweitert werden müssen, aber ich bin immer noch sehr daran interessiert, dass dies in Dokumentationsform, Pipenv oder anderweitig geht. Haben Sie Interesse, einen Pull-Request einzusenden? Gerne helfe ich bei der Ausarbeitung des Artikels.
Was Poesie angeht, bin ich persönlich kein Fan, aber sie macht viele richtige Dinge. Es sollte wahrscheinlich nicht in Pipenv-Dokumenten erwähnt werden, da es gegen einige Best Practices verstößt, zu denen Pipenv-Entwickler die Leute drängen möchten, aber es sollte erwähnt werden, wenn die Diskussion in pypa-dev oder ähnlichem stattfindet, um ein vollständiges Bild davon zu erhalten, wie die Verpackung ist Ökosystem derzeit ist.
Poesie kann auch mehr Aufmerksamkeit und Beitrag gebrauchen. Dies wäre das Beste für die Community, einschließlich Pipenv. Mit praktikablen Entscheidungen können die Leute ihre Entscheidungen abwägen, anstatt sich kopfüber in Pipenv zu beschweren und sich zu beschweren, dass es nicht das tut, was sie erwarten. Ein guter Wettbewerb zwischen Bibliotheken kann auch technische Verbesserungen im Bereich der Abhängigkeitsauflösung vorantreiben, was Pipenv und Poesie beide tun (und beide nicht perfekt). Wir können viel voneinander lernen.
@uranusjr Ja, ich denke, nur wenige Dinge wurden geklärt und verdienen es, mit einem breiteren Publikum geteilt zu werden. Ihre Hilfe ist wirklich willkommen.
Wie wäre es mit "Paardokumentationserstellung"? Ich denke, dass es im Moment am effektivsten wäre, daran im kleinen Maßstab von nur zwei Personen zu arbeiten.
Denkbar sind (möglicherweise mit ein oder zwei Iterationen):
Wenn Sie Lust haben, es selbst zu schreiben (basierend auf dem, was besprochen wurde) und mich als Rezensenten haben, würde ich mich nicht beschweren.
Ich werde Sie per E-Mail kontaktieren, um die nächsten Maßnahmen zu vereinbaren.
@vlcinsky Ich bin auch als @uranusjr
auf PySlackers (einem Slack-Workspace) verfügbar, wenn Sie Echtzeit-Interaktion bevorzugen. Pipenv hat dort einen Kanal ( #pipenv
).
@uranusjr Das meinte ich mit Anstrengung sammeln. Python braucht dringend einen guten Paketmanager wie cargo. Das Python-Ökosystem verblasst im Vergleich zu den anderen Sprachen aufgrund des Fehlens einer Standardmethode. Und pipenv
wird da nicht helfen, denke ich.
Was mich stört, ist, dass pipenv
selbst als the officially recommended Python packaging tool
pipenv
bewirbt, obwohl es kein Verpackungstool ist, im Gegenteil, was für die Benutzer irreführend ist. Es ist lediglich ein Abhängigkeitsmanager, der mit einem Virtualenv-Manager gekoppelt ist.
Sie sagen auch, dass es von Cargo, npm, Garn inspiriert wurde, die Verpackungswerkzeuge zusammen mit Abhängigkeitsmanagern sind, während Rohrleitungen dies nicht sind.
Und hier ist der Fehler von pipenv
, es trübt nur das Wasser, da die Leute immer noch die gleichen Fehler machen wie zuvor mit requirements.txt
vs. setup.py
. Projekte werden deshalb immer noch schlecht mit schlecht definierten Abhängigkeiten in ihren setup.py
verpackt. Das ist es, was Projekte wie cargo richtig gemacht haben: Sie kümmern sich um alle Aspekte der Entwicklung von Projekten/Anwendungen, um eine Konsistenz zu gewährleisten, während ein Projekt wie pipenv
dies nicht tut.
Und wenn du sagst:
was Pipenv und Poesie beide tun (und beide nicht perfekt)
Was meinen Sie? Nach allem, was ich gesehen habe, ist ihr Abhängigkeitsmanager viel widerstandsfähiger als der von pipenv
bereitgestellte. Der einzige Nachteil ist, dass sie die PyPI JSON API verwenden, die manchmal aufgrund schlecht veröffentlichter Pakete keine Abhängigkeitsinformationen enthält.
Wie auch immer, ich denke, wie Sie schon sagten, dass beide Projekte voneinander lernen können.
Und noch eine Sache, wie sieht die Zukunft von pipenv aus, wenn pip letztendlich die Pipfile
handhabt? Wird es nur ein Virtualenv-Manager sein?
Wenn der Poetry-Abhängigkeitsmanager auf der Json-API basiert, ist dies nicht nur manchmal aufgrund von "schlecht veröffentlichten Paketen" falsch, sondern es wird auch sehr eingeschränkt, was es tatsächlich richtig auflösen kann. Die Warehouse-Json-API veröffentlicht die _aktuellsten_ Abhängigkeiten, auch wenn Sie mit einer alten Version arbeiten, und wenn diese Informationen überhaupt vorhanden sind. Früher haben wir auch die json-API integriert, es war großartig, weil es schnell war, aber das Infrastrukturteam sagte uns, wir sollten ihr nicht vertrauen. Es scheint ein bisschen unaufrichtig, etwas als widerstandsfähig zu bezeichnen, wenn es sich zunächst auf eine unzuverlässige Quelle verlässt.
Letztendlich bestehen die Herausforderungen darin, tatsächlich einen Abhängigkeitsgraphen zu erstellen, der eine Setup-Datei ausführte, da das Paketieren derzeit so funktioniert. Es führt einfach kein Weg daran vorbei. Ein Abhängigkeitsdiagramm, das auf meinem Computer aufgelöst wird, kann sich sogar für dasselbe Paket von einem unterscheiden, das auf Ihrem Computer aufgelöst wird.
Es ist einfach, mit der Hand zu winken und zu sagen: 'Nun, macht das Pipenv nicht einfach zu einem Virtualenv-Manager, wenn pip eine Pip-Datei lesen kann?' Nein. Pipenv ist ein Abhängigkeitsmanager. Es verwaltet idempotente Umgebungen und generiert eine reproduzierbare Lockfile. Mir ist klar, dass Ihnen dies trivial erscheinen muss, weil Sie es wegwinken und dieses Tool auf einen Virtualenv-Manager reduzieren, aber das ist es nicht. Wir lösen Sperrdateien auf und fügen Markierungen für Python-Versionen hinzu, die Sie nicht haben, nicht verwenden, und halten diese verfügbar, damit Sie plattform- und python-Versionen präzise bereitstellen und reproduzieren können. Wir verwenden verschiedene Auflösungsmethoden, einschließlich der Behandlung lokaler Räder und Dateien, vcs-Repositorys (wir lösen dort auch den Graphen auf), Remote-Artefakte, Pypi-Pakete, private Indizes usw.
Am Ende des Tages _will_ pipfiles handhaben, das ist der Plan, der Plan seit der Erstellung des Formats. Aber das ist dasselbe wie die Frage "Aber was ist, wenn pip mit Anforderungsdateien umgehen kann?" Die Frage ist im Grunde identisch. Pip kann dieses Format installieren. Es ist für keine der von mir beschriebenen Funktionen wirklich relevant, außer dass wir die Dateien auch installieren (übrigens mit pip).
@techalchemie
Die Warehouse-Json-API veröffentlicht die neuesten Abhängigkeiten, auch wenn Sie mit einer alten Version arbeiten, und wenn diese Informationen überhaupt vorhanden sind
Das ist einfach falsch, Sie können eine bestimmte Versionsabhängigkeit erhalten, indem Sie https://pypi.org/pypi/{project}/{release}/json
aufrufen. Wenn Sie nur https://pypi.org/pypi/{project}/json
aufrufen, erhalten Sie sicher nur die letzten Abhängigkeiten, aber Sie können tatsächlich die richtigen Abhängigkeiten erhalten.
Und der Paketierungs-/Publishing-Teil von Python-Projekten muss wirklich verbessert werden, denn am Ende werden alle davon profitieren, da die JSON-API zuverlässig verwendet werden kann.
Es verwaltet idempotente Umgebungen und generiert eine reproduzierbare Lockfile.
Wir lösen Sperrdateien auf und fügen Markierungen für Python-Versionen hinzu, die Sie nicht haben, nicht verwenden, und halten diese verfügbar, damit Sie plattform- und python-Versionen präzise bereitstellen und reproduzieren können.
Und poetry
. Und Sie können dafür sorgen, dass die JSON-API nicht verwendet wird, um dieselbe Auflösungsmethode wie pipenv
(mit pip-tools) bereitzustellen. Siehe https://github.com/sdispater/poetry/issues/37#issuecomment -379071989 und es wird immer noch widerstandsfähiger sein als pipenv
(https://github.com/sdispater/poetry#dependency-resolution )
@zface Ich werde dies ein letztes Mal sagen, bitte bringen Sie dies zu einer höheren Stelle in der Hierarchie. Pipenv erklärt sich nicht selbst als das offiziell empfohlene Python-Paketierungstool; es sagt das, weil es so ist . Wenn Sie das für unangemessen halten, teilen Sie dies den Beamten mit, die Pipenv empfehlen . Bitte legen Sie diese Dinge nicht auf Pipenv dev. Dies ist der falsche Ort, um sich zu beschweren, und Sie können hier unmöglich eine Lösung für Ihre Beschwerden finden. Dort erhalten Sie auch bessere Antworten auf technische Fragen. Dies ist ein Issue-Tracker für Pipenv, kein Diskussionsforum für Python-Paketierungstools und wie Python-Paketierung durchgeführt wird.
Pipenv verlässt sich nicht nur auf pip-tools zur Auflösung, bitte hören Sie auf, unsere Software auf Einzeiler zu reduzieren, die Unverständnis zeigen. Ich weiß sehr gut, wie die PyPI-API funktioniert, ich habe direkt mit dem Team gesprochen, das sie implementiert hat.
Das ist einfach falsch,
Eine solche Haltung ist hier nicht erwünscht. Gehen Sie nicht davon aus, dass wir nicht verstehen, wovon wir sprechen. Bitte üben Sie Höflichkeit.
es wird immer noch widerstandsfähiger sein als pipenv (https://github.com/sdispater/poetry#dependency-resolution)
Pipenv reduziert derzeit keine Abhängigkeitsdiagramme. Es ist töricht, auf ein bestimmtes Problem hinzuweisen, bei dem ein Baum abgeflacht wurde, und zu behaupten, dass das gesamte Werkzeug daher sowohl besser als auch widerstandsfähiger ist. Sie beweisen immer wieder, dass Sie nur hier sind, um Pipenv zu beleidigen und Poesie zu fördern. Bitte machen Sie sich auf den Weg, dieses Verhalten ist nicht erwünscht.
Ich stimme zu, dass die Diskussion weit vom Thema abweicht, da versucht wurde, die "bewährten Praktiken" in der Umgebung von Pipenv zu nutzen.
Jedoch,
[...] werden immer noch die gleichen Fehler wie zuvor mit Requirements.txt vs setup.py machen. Projekte werden deshalb immer noch schlecht mit schlecht definierten Abhängigkeiten in ihrer setup.py verpackt.
Ich teile diese Meinung, neue Entwickler dazu zu bringen, ihren eigenen Python-Code erfolgreich zu paketieren, ist eigentlich komplex, zu komplex, erfordert viel zu viel Online-Dokumentation.
Aber es ist nicht Sache von pipenv oder einer anderen Paketabhängigkeit, damit vollständig umzugehen. Wir konnten die Geschichte nicht umschreiben. Wir als Gemeinschaft müssen einen Weg finden, die Python-Toolkette Schritt für Schritt zu modernisieren.
Und Pipenv (und wahrscheinlich Poesie) ist ein sehr guter Schritt nach vorne.
Auf der einen Seite Pipfile
für die Anwendung und setup.py
für Bibliotheken auf der anderen Seite pflegen zu müssen, ist ein Kinderspiel. Egal wie schwer wir es mit vielen Worten, langen Artikeln und Good-Practice-Leitfäden erklären, es ist zu komplex für das, was es ist. Ich stimme voll und ganz zu, dass es im Moment so ist, aber es sollte uns nicht daran hindern, uns einen besseren und sichereren Weg vorzustellen.
Am Ende möchte ich als Entwickler ein einziges Tool, vielleicht mit zwei verschiedenen Modi, das mir hilft und mein Leben so einfach wie möglich macht.
Sie sollten eine Möglichkeit sein, nur den Teil zu extrahieren, der requirements.txt/Pipfile
aus Libs wie PBR macht, um eine Art 'easy setup.py' vorzuschlagen, einen Pipfile-fähigen Wrapper um install_requires
, ohne all das unerwünschte Verhalten, das pbr mit sich bringt, und packe das in einen dedizierten setuptools-Wrapper, der nur das tut.
So könnten wir das Beste aus jeder Welt haben:
Pipfile
(in Bibliotheken und Anwendungen versioniert)Pipfile.lock
(nur für Anwendungen versioniert)pipfile_setuptools
, install_requires_pipfile
?) verwenden, das eine Abhängigkeit der ersten Ebene wäre, deren Aufgabe nur darin besteht, Pipfile
in install_requires
.Dies ist ein weiteres Projekt, das nicht mit pipenv
, aber dennoch eine generische Pipfile
Parserbibliothek benötigt. Was denken Sie?
@gsemet Nach meinem Verständnis hat PyPA versucht, dies stattdessen mit pyproject.toml zu füllen, angeführt von flit . Sie müssen zuerst mit ihnen (bei pypa-dev oder distutils-sig) darüber sprechen, bevor Sie Pipfile als Quellformat verwenden. Was das Parsen von Pipfile (und der Sperrdatei) angeht , wird dies in
Bearbeiten: Bitte senden Sie mir eine Nachricht, wenn Sie sich entscheiden, eine Diskussion darüber in einer der Mailinglisten zu beginnen. Ich habe einige Ideen, wie wir die beiden Teile der Python-Paketverteilung zusammenbringen können.
Ich muss zugeben, dass ich ein bisschen traurig bin, Abhängigkeiten zu sehen, die in pyproject.toml
deklariert sind (was die Rollen wie setup.cfg
von PBR übernimmt), während PyPa auch Pipfile
....
Danke für den Hinweis auf Flit und Pipfile. Es gibt auch die Pipenvlib von Kennethreitz , die leichter erscheint.
Die setup.cfg von PBR scheint im Vergleich zur offiziellen Dokumentation vollständiger zu sein (z. B.: data_files
) und die Wiederverwendung einer Datei, die bereits mit mehreren Tools (flake8, pytest, ...) geteilt wurde, kann dieselbe Datei verwenden, wodurch die Anzahl der Datei im Stammverzeichnis eines Python-Projekts)
Hilfreichster Kommentar
@ Moritz90 Mehrere Mailinglisten von Python wären gute Orte, um diese Diskussion zu führen.
pypa-dev ist am besten umgebende Ökosystem. Ich würde wahrscheinlich hier anfangen, wenn ich eine ähnliche Diskussion posten würde.
python-ideas ist ein Ort, um Ideen zu diskutieren, und hat eine ziemlich hohe Sichtbarkeit für die gesamte Python-Community. Es wäre auch ein guter Ausgangspunkt, wenn Sie dies auf die PEP-Ebene bringen möchten (ich denke, Sie würden es irgendwann tun).