Pipenv: [Frage] Wie integriere ich mit setup.py?

Erstellt am 7. Feb. 2017  ·  38Kommentare  ·  Quelle: pypa/pipenv

Mit requirements.txt kann ich es tun:

from pip.req import parse_requirements
requirements = [str(r.req) for r in
                parse_requirements('requirements.txt', session=False)]
test_requirements = [str(r.req) for r in
                     parse_requirements('requirements-test.txt', session=False)]

Wie kann ich dasselbe mit Pipfile tun?

Hilfreichster Kommentar

Erstens, Haftungsausschluss: Meine Expertise liegt hauptsächlich bei lib-Paketen. Ich könnte einige Punkte übersehen. Ich habe das Recht, falsch zu liegen, und ich bin bereit, es zu nutzen!
Das hat mich auch ein paar Mal am Kopf kratzen lassen. Ich hätte wirklich gerne eine Bewertung dazu.

Kommen wir nun dazu.

Ich beginne mit dieser Aussage @elgertam :

[...] meine Verwendung von Pipfile lässt mich denken, dass install_requires wirklich fast identisch mit dem ist, was in Pipfile steht. Wenn ich numpy brauche, installiere ich numpy per Pipenv und ein neuer Eintrag kommt in die [Pakete]-Gruppe meines Pipfiles [...]

Sie haben numpy zu Ihrer Umgebung hinzugefügt, Sie haben numpy nicht zu den Abhängigkeiten Ihrer App hinzugefügt.
Das sind zwei verschiedene Dinge. Lesen Sie weiter, Sie werden sehen, was ich meine.

Mit anderen Worten, meine Verwendung unterscheidet sich völlig von der requirements.txt, die ich früher nur generiert habe, bevor ich sie mit pip freeze > requirements.txt festgeschrieben habe.

Überraschenderweise unterscheidet sich Ihre Verwendung nicht so sehr, wenn Sie darüber nachdenken:

  • Ihr vorheriger Workflow: pip install stuff -> pip freeze > requirements.txt -> füttern Sie install_requires von requirements.txt
  • Ihr neuer (versuchter) Workflow: pipenv install stuff -> Pipfile automatisch aktualisiert -> versucht, install_requires mit Pipfile zu füttern.
  • Was ist die beabsichtigte Idee: Dinge zu install_requires -> pipenv install -> Umgebung und Pipfile.lock werden aktualisiert.

Und für diese beabsichtigte Funktionsweise benötigen Sie einen Pipfile , der besagt, dass Sie Ihre App installieren möchten.
So etwas wie die von @isobit verlinkten requests Pipfile .

Oder ein Beispiel:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]
pytest = ">=2.8.0"
tox = "*"

[packages]
"-e ." = "*"

Ihr Pipfile soll Ihre Umgebung beschreiben, nicht die Abhängigkeiten eines Pakets. Wie Sie sehen, definiert das obige Pipfile , was ich installieren möchte, nämlich das lokale Paket im bearbeitbaren Modus.

Dies mag etwas "nutzlos" aussehen, da im Moment alles von einem einzigen Paket gesteuert wird, aber sagen wir, Sie möchten Ihre App installieren, aber mit requests[security] , aber es ist keine strikte Abhängigkeit von Ihrer App, Ihnen mach pipenv install requests[security] und dann:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]
pytest = ">=2.8.0"
tox = "*"

[packages]
"-e ." = "*"
requests = { extras = ['security'] }

Und voilà, hier ist ein Beispiel für den Unterschied zwischen Ihren abstrakten Anforderungen und Ihren konkreten Anforderungen. Dasselbe gilt, wenn Sie gunicorn oder etwas anderes, das in der Umgebung benötigt wird, installieren möchten, aber das ist nicht Teil der App selbst.

Was übersehe ich hier, @vphilippon? Warum sind die [Pakete] von Pipfile zu eingeschränkt, um sie in install_requires oder tests_require zu verwenden?

Wenn ich das gut genug erklärt habe, können Sie sehen, dass es genau umgekehrt sein sollte.
Sie legen Ihre Abhängigkeiten in install_requires ab, Sie legen Ihr Paket in Pipfile ab, und dann erhalten Sie eine Umgebung mit einem Pipfile.lock für die Reproduzierbarkeit (da es Ihre Paketabhängigkeiten).

Für test_require muss ich zugeben, dass ich mir nicht sicher bin, ob das alles passt. IIRC, es ist eine setuptools spezifische Funktion. Wir könnten argumentieren, dass es sich um eine Reihe abstrakter Abhängigkeiten zum Testen handelt, und erwarten, dass pipenv diese auflöst und installiert, was dann pipenv install --dev für alle Pakete ausführt, aber ich habe das Gefühl, dass das nicht ganz richtig ist. Ich habe keine klare Idee oder Meinung dazu und die Gründe dafür, sorry.

Ich hoffe das ergibt alles irgendwie Sinn.

Alle 38 Kommentare

Sie sollten dies mit dem folgenden Code erreichen können. Dadurch wird das Pipfile aus Ihrem aktuellen Projekt geladen und die Abhängigkeiten in einer Pip-kompatiblen Liste zurückgegeben.

from pipenv.project import Project
from pipenv.utils import convert_deps_to_pip

pfile = Project(chdir=False).parsed_pipfile
requirements = convert_deps_to_pip(pfile['packages'], r=False)
test_requirements = convert_deps_to_pip(pfile['dev-packages'], r=False)

Lass uns wissen, wenn du weitere Fragen hast :)

Das oben genannte ist sehr hilfreich. Ich bin auf Probleme mit setup.py gestoßen, je nachdem, ob Pipenv in einer virtuellen Umgebung installiert ist, bevor setup.py install (oder irgendetwas anderes) ausgeführt werden kann. Die einzigen Lösungen für dieses Problem, die mir einfallen, sind entweder die Bereitstellung von Pipenv in einem Projekt, was alles andere als ideal erscheint, oder sogar das Hacken der setup.py, um Pipenv zu installieren, bevor versucht wird, die from pipenv... -Importe auszuführen, was scheint falsch. Hat jemand eine Idee oder bessere Lösungen als diese?

Sollten wir anderen in der Python-Community (PyPA usw.) vorschlagen, Pipenv einfach als offiziell enthaltenes Tool in zukünftigen Python-Versionen zu segnen? 😄

Würde es helfen, pipenv zu setup_requires hinzuzufügen ? Es sieht so aus, als ob es auch notwendig sein könnte, es zu install_requires hinzuzufügen, was unglücklich erscheint.

Mach das nicht.

@kennethreitz was meinst du mit "dies"? Meinst du die Integration mit setup.py, die Lösung von @nateprewitt oder die letzten beiden Vorschläge?

Woher sollten Benutzer also wissen, dass sie pipenv installiert haben müssen?

Da pipenv ein Tool ist, mit dem Dinge installiert werden, und nicht umgekehrt, gibt es keinen Grund, es in Ihrer setup.py anzufordern. Wovor Kenneth warnt, ist der Import von pipenv in setup.py, da es sich um eine CLI-Anwendung handelt und Probleme verursachen kann.

Am 17. Oktober 2017 um 9:37 Uhr schrieb Iddan Ahahronson [email protected] :

Woher sollten Benutzer also wissen, dass sie pipenv installiert haben müssen?


Sie erhalten dies, weil Sie diesen Thread abonniert haben.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf GitHub an oder schalten Sie den Thread stumm.

Wie kann ich also den Code von @nateprewitt - in setup.py verwenden?

@iddan : Ich habe versucht, das Bootstrapping-Problem von Pipenv zu lösen, indem ich einfach eine Version von Pipenv in mein Projektskelett (https://github.com/elgertam/cookiecutter-pypackage/blob/master/%7B%7Bcookiecutter.project_slug%7D %7D/setup.py). Bisher hatte ich keine Probleme, obwohl ich nicht sagen kann, dass ich viele Möglichkeiten hatte, es in einer Situation zu testen, in der ich ein Paket mit setup.py installiere.

Ich kann verstehen, warum wir uns Sorgen machen würden, beim Laden von setup.py keine CLI auszuführen, aber soweit ich das beurteilen kann, ist der Code, den ich verwende (kopiert und eingefügt aus dem Post von @nateprewitt hier), ziemlich sicher.

Ich denke, dieser Hack wird nicht mehr notwendig sein, wenn pip genügend Interna hat, um das Pipfile-Format zu verstehen.

@iddan , um es klar zu sagen, dieser Code dient ausschließlich dazu, Abhängigkeiten von Pipfiles in ein Format im Requirements.txt-Stil zu konvertieren, das pip lesen kann. Es sieht so aus, als hätte Kenneth etwas aus dem ursprünglichen Beitrag redigiert, aber ich bin mir nicht sicher, was.

Pipenv ist als Umgebungsverwaltungs- und Bereitstellungstool gedacht, nicht zur Verteilung wie setup.py. Wir empfehlen dringend, zu dokumentieren, dass Sie ein Pipfile verwenden, und möglicherweise auf pipenv.org zu verlinken, um Installationsanweisungen zu erhalten. Behandeln Sie dies genauso wie pip, es wird nicht erwartet, dass ein Benutzer pip jedes Mal installiert, wenn er ein neues Python-Paket installiert.

Ich verstehe das vollkommen. Was ich nicht verstehe, ist, was Sie erwarten, wenn ein Benutzer ein Paket mit diesem Skript herunterlädt und pipenv nicht installiert hat

@nateprewitt , wenn wir dann ein Paket verteilen wollen (durch die üblichen Mittel mit pip ), sollten wir eine Kopie der Abhängigkeitsliste in setup.py oder requirements.txt pflegen ? Ich hatte gehofft, mein Pipfile als Single Source of Truth zu verwenden.

Zur Verdeutlichung gehe ich davon aus, dass der Code in der ersten Antwort als Teil eines Builds ausgeführt werden soll und nicht tatsächlich in einem setup.py verwendet wird.

Wenn ich mich nicht stark irre, kann der Code in https://github.com/kennethreitz/pipenv/issues/209#issuecomment -278185133 sicher verwendet werden, wenn Sie ein Rad bauen (=binäre Distanz), aber nicht wenn du baust sdist (=source dist).

Bei Rädern wird setup.py nicht in das Paket aufgenommen (sondern während der Erstellungszeit ausgewertet, und Metadatendateien werden basierend auf den gesammelten Informationen erstellt). Bei Rädern wird setup.py niemals auf der Maschine ausgeführt, auf der das Paket installiert wird, sondern nur dort, wo es gebaut wurde.

Mit sdist wird setup.py tatsächlich auf dem Installationsrechner ausgeführt und daher muss pipenv dort verfügbar sein.

Oh ja. @tuukkamustonen , mein spezieller Anwendungsfall ist ein sdist. Da ich nicht verlangen möchte, dass der Paketbenutzer pipenv installiert, bevor er ein pip install , nehme ich an, dass ich beim Ableiten meiner install_requires außerhalb von setup.py feststecke

Wenn ich richtig lese, glaube ich, dass Kenneth und die anderen Betreuer nicht wollen, dass wir Pipenv als Projektabhängigkeit behandeln, wie wir es für pytest tun würden, oder sogar als normale Paketabhängigkeit. Idealerweise sollten wir Pipenv genauso installieren und aktualisieren wie pip selbst, dh pip wird installiert, wenn Python installiert wird oder wenn ein virtualenv wird erstellt. Das meinte Kenneth, als er sagte: "Tu das nicht."

Trotzdem hat @isobit meine Gedanken wiederholt, dass Pipfile die einzige Quelle der Wahrheit sein sollte. Ich sehe zwei überzeugende Anwendungsfälle für die Bevorzugung von Pipfile (und es gibt noch andere): Erstens ist eine CI/CD-Pipeline, die von Pipfile abhängt, um die Build-Umgebung einzurichten, viel robuster als eine, die von der Requirements.txt abhängt; und zweitens kann ein Mitwirkender blindlings versuchen, ein Pipfile-basiertes Projekt zu installieren, und kann frustriert sein, wenn python setup.py install nicht so funktioniert, wie er es erwartet. In Anbetracht der Tatsache, dass weder Pipenv noch Pipfile-fähiges Pip bisher Standard-Python-Tools sind und Pipenv tatsächlich die Referenzimplementierung für Pipfile ist, haben wir nur wenige Möglichkeiten, das Problem zu lösen:

1) Geben Sie in Ihrer Projektdokumentation an, dass Ihr Projekt von Pipenv abhängt. Sie können sich immer noch auf Pipenv in Ihrem setup.py , und dies wird brechen, wenn Pipenv nicht in Ihrer Python-Umgebung installiert ist. Konkret müsste ein Mitwirkender an Ihrem Code Pipenv manuell in seinem virtualenv installieren, um das Projekt mit setup.py zu installieren.
2) Setup.py ist immer noch von requirements.txt abhängig, das Sie regelmäßig basierend auf Ihren Pipfile generieren. Dies bleibt vollständig kompatibel mit pip und setuptools , erfordert jedoch, dass jeder Betreuer die requirements.txt generiert, wenn das Projekt erstellt und bereitgestellt wird. Eine mögliche Variation davon wäre, dass eine CI/CD-Pipeline die requirements.txt zur Buildzeit aktualisiert.
3) Bieten Sie eine Version von Pipenv in einem Projekt an und rufen Sie es mit from _vendor.pipenv.project import Project... innerhalb setup.py . Eine Variante davon könnte darin bestehen, nur aus der herstellerspezifischen Version zu importieren, wenn der globale Import fehlschlägt.
4) Eine andere Option, die hier nicht vorgestellt wird und an die ich nicht klug genug bin, um darüber nachzudenken.

Ich persönlich verwende (3) (siehe https://github.com/kennethreitz/pipenv/issues/209#issuecomment-300550425), bis Pipfile mehr zu einem gemeinsamen Standard wird, an diesem Punkt werde ich keines meiner Projekte mehr haben hängen direkt vom Pipenv-Code ab, da Pipenv eindeutig als Werkzeug zum Verwalten einer virtuellen Umgebung auf der Grundlage einer Pipfile und nicht unbedingt als Pipfile-Bibliothek selbst gedacht zu sein scheint.

Ich hoffe, dies klärt das Problem basierend auf dem, was ich hier gelesen habe, aber wenn ich mich falsch ausgedrückt oder etwas Ungeheuerliches gesagt habe, lass es mich bitte wissen @nateprewitt.

Ich habe das Gefühl, dass das Problem hier von einem ursprünglichen Missbrauch (IMO) des requirements.txt herrührt. Abgesehen von der Verwendung von pipenv .

Ich verweise auf diesen wunderbaren Artikel von Donald Stufft, setup.py vs requirements.txt:
https://caremad.io/posts/2013/07/setup-vs-requirement/

TL;DR (aber Sie sollten es trotzdem lesen): setup.py 's install_requires soll die Anforderungen (Abhängigkeiten) eines Pakets beschreiben. Die requirements.txt (die hier durch die Kombination $ Pipfile / Pipfile.lock ersetzt würde) sollte verwendet werden, um aufzulisten, welche genauen Pakete verwendet werden, um die Anforderungen zu erfüllen, basierend auf der Metadaten aus dem setup.py , um eine reproduzierbare Umgebung zu erstellen.
Das Auffüllen der install_requires von den requirements.txt ist wie ein Rückwärtsgehen.

setup.py 's install_requires =/= requirements.txt (oder Pipfile / Pipfile.lock ).
Pipfile (oder besser gesagt Pipfile.lock ) sollte die Single Source of Truth der Pakete sein, die in der App-Umgebung installiert werden sollen.
setup.py 's install_requires stellt Metadaten bereit, die zum Generieren eines gültigen Pipfile.lock verwendet werden.

Ich denke, daher kommt die Reibung. Ich hoffe, das macht Sinn.

Mir gefällt diese Antwort sehr, Vincent, und ich stimme absolut zu, dass Pipfile.lock ein vollständiger (und besserer) Ersatz für requirements.txt ist.

Nachdem ich Pipenv jetzt seit einigen Monaten verwende, lässt mich meine Verwendung von Pipfile denken, dass install_requires wirklich fast identisch mit dem ist, was in Pipfile steht. Wenn ich numpy brauche, gebe ich pipenv install numpy und einen neuen Eintrag in die [packages] -Gruppe meines Pipfiles ein: numpy = "*" . Mit anderen Worten, meine Verwendung unterscheidet sich grundlegend von requirements.txt , die ich früher nur generiert habe, bevor ich sie mit pip freeze > requirements.txt habe.

Vielleicht ist dies nur eine seltsame Art und Weise, wie ich Pipenv verwende, und ich gehe gegen den Strom (ich installiere mein virtualenv auch in .venv/ im Projektverzeichnis, also bin ich ein abtrünniger Pythonista). Fall kann ich mich leicht an die Konvention der Python-Community halten, eine Trennwand zwischen setup.py und Pipfile | zu haben Pipfile.lock | requirements.txt .

Was übersehe ich hier, @vphilippon?

Danke für die Info, @vphilippon. Vielleicht gehen wir das rückwärts an, es klingt so, als wollten wir wirklich das Gegenteil – eine Möglichkeit, abstrakte Deps von install_requires in unserem Pipfile zu verwenden, wie Donald in Bezug auf -e . in requirements.txt erwähnt

Wird dies bereits von der Pipfile-Syntax abgedeckt? Ich habe gerade bemerkt, dass die Anforderungsbibliothek Pipfile "e1839a8" = {path = ".", editable = true, extras=["socks"]} in ihrem Paketabschnitt verwendet. Etwas Ähnliches ist in den Pipfile-Beispielen ersichtlich , aber ich sehe keine andere Dokumentation.

Erstens, Haftungsausschluss: Meine Expertise liegt hauptsächlich bei lib-Paketen. Ich könnte einige Punkte übersehen. Ich habe das Recht, falsch zu liegen, und ich bin bereit, es zu nutzen!
Das hat mich auch ein paar Mal am Kopf kratzen lassen. Ich hätte wirklich gerne eine Bewertung dazu.

Kommen wir nun dazu.

Ich beginne mit dieser Aussage @elgertam :

[...] meine Verwendung von Pipfile lässt mich denken, dass install_requires wirklich fast identisch mit dem ist, was in Pipfile steht. Wenn ich numpy brauche, installiere ich numpy per Pipenv und ein neuer Eintrag kommt in die [Pakete]-Gruppe meines Pipfiles [...]

Sie haben numpy zu Ihrer Umgebung hinzugefügt, Sie haben numpy nicht zu den Abhängigkeiten Ihrer App hinzugefügt.
Das sind zwei verschiedene Dinge. Lesen Sie weiter, Sie werden sehen, was ich meine.

Mit anderen Worten, meine Verwendung unterscheidet sich völlig von der requirements.txt, die ich früher nur generiert habe, bevor ich sie mit pip freeze > requirements.txt festgeschrieben habe.

Überraschenderweise unterscheidet sich Ihre Verwendung nicht so sehr, wenn Sie darüber nachdenken:

  • Ihr vorheriger Workflow: pip install stuff -> pip freeze > requirements.txt -> füttern Sie install_requires von requirements.txt
  • Ihr neuer (versuchter) Workflow: pipenv install stuff -> Pipfile automatisch aktualisiert -> versucht, install_requires mit Pipfile zu füttern.
  • Was ist die beabsichtigte Idee: Dinge zu install_requires -> pipenv install -> Umgebung und Pipfile.lock werden aktualisiert.

Und für diese beabsichtigte Funktionsweise benötigen Sie einen Pipfile , der besagt, dass Sie Ihre App installieren möchten.
So etwas wie die von @isobit verlinkten requests Pipfile .

Oder ein Beispiel:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]
pytest = ">=2.8.0"
tox = "*"

[packages]
"-e ." = "*"

Ihr Pipfile soll Ihre Umgebung beschreiben, nicht die Abhängigkeiten eines Pakets. Wie Sie sehen, definiert das obige Pipfile , was ich installieren möchte, nämlich das lokale Paket im bearbeitbaren Modus.

Dies mag etwas "nutzlos" aussehen, da im Moment alles von einem einzigen Paket gesteuert wird, aber sagen wir, Sie möchten Ihre App installieren, aber mit requests[security] , aber es ist keine strikte Abhängigkeit von Ihrer App, Ihnen mach pipenv install requests[security] und dann:

[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true

[dev-packages]
pytest = ">=2.8.0"
tox = "*"

[packages]
"-e ." = "*"
requests = { extras = ['security'] }

Und voilà, hier ist ein Beispiel für den Unterschied zwischen Ihren abstrakten Anforderungen und Ihren konkreten Anforderungen. Dasselbe gilt, wenn Sie gunicorn oder etwas anderes, das in der Umgebung benötigt wird, installieren möchten, aber das ist nicht Teil der App selbst.

Was übersehe ich hier, @vphilippon? Warum sind die [Pakete] von Pipfile zu eingeschränkt, um sie in install_requires oder tests_require zu verwenden?

Wenn ich das gut genug erklärt habe, können Sie sehen, dass es genau umgekehrt sein sollte.
Sie legen Ihre Abhängigkeiten in install_requires ab, Sie legen Ihr Paket in Pipfile ab, und dann erhalten Sie eine Umgebung mit einem Pipfile.lock für die Reproduzierbarkeit (da es Ihre Paketabhängigkeiten).

Für test_require muss ich zugeben, dass ich mir nicht sicher bin, ob das alles passt. IIRC, es ist eine setuptools spezifische Funktion. Wir könnten argumentieren, dass es sich um eine Reihe abstrakter Abhängigkeiten zum Testen handelt, und erwarten, dass pipenv diese auflöst und installiert, was dann pipenv install --dev für alle Pakete ausführt, aber ich habe das Gefühl, dass das nicht ganz richtig ist. Ich habe keine klare Idee oder Meinung dazu und die Gründe dafür, sorry.

Ich hoffe das ergibt alles irgendwie Sinn.

@vphilippon Du hast es ganz gut erklärt und ich denke, du hast mich überzeugt.

TL;DR: Die abstrakten, absolut notwendigen Abhängigkeiten in setup.py , dann Kontext (und damit Konkretheit) in Pipfile und Pipfile.lock hinzufügen, inklusive der fantastischen "-e ." = "*" Eintrag.

Ein Problem mit https://github.com/kennethreitz/pipenv/issues/209#issuecomment -337409290 besteht darin, dass wir keine reproduzierbare Umgebung erhalten, wenn wir unsere App auf einem Server bereitstellen möchten.

Ich meine, normalerweise, wenn wir eine _Bibliothek_ entwickeln, die in anderen Projekten verwendet wird, wollen wir, dass unsere install_requires ziemlich locker sind (=keine Bindung an genaue Versionen). Jawohl. Aber wenn wir eine Web-App (oder eine beliebige App) erstellen und auf einem Remote-Server oder Docker-Container bereitstellen, möchten wir wahrscheinlich feste Abhängigkeiten. Selbst wenn wir genaue Versionen in install_requires angeben, werden transitive Abhängigkeiten nicht gesperrt und die Installation kann tatsächlich eine andere (neuere) Version einer transitiven Abhängigkeit herunterladen, was Ihre Bereitstellung beschädigen kann.

(Das manuelle Deklarieren exakter Versionen von transitiven Abhängigkeiten ist keine Option - viel zu umständlich.)

In diesem Anwendungsfall sollten wir uns auf eine Sperrdatei im requirements.txt -Stil verlassen (die genaue Versionen sogar für transitive Abhängigkeiten angibt). Allerdings scheint es nicht so, als ob es pipenv erlaubt, Entwicklungsanforderungen in pipenv lock -r (z. B. pipenv lock --no-dev -r ) auszuschließen, sodass wir tatsächlich solche requirements.txt herstellen könnten (das kann dann sein in install_requires einlesen)?

Ich zitiere den Artikel von Donald Stufft:

Eine Anwendung hat normalerweise eine Reihe von Abhängigkeiten, oft sogar eine sehr komplexe Reihe von Abhängigkeiten, gegen die sie getestet wurde. Da es sich um eine bestimmte Instanz handelt, die bereitgestellt wurde, hat sie normalerweise weder einen Namen noch andere paketbezogene Metadaten. Dies spiegelt sich in den Fähigkeiten einer Pip-Anforderungsdatei wider.

Mit anderen Worten: Die App ist nicht das Paket. Die App ist die Umgebung, in der eine Reihe konkreter Abhängigkeiten installiert sind. Eine App-Abhängigkeit sollte durch ein requirements.txt (oder Pipfile / Pipfile.lock ) dargestellt werden, nicht durch ein einzelnes Paket install_requires .

Persönlich würde ich so weit gehen zu sagen, dass der vollständige Satz der gepinnten Abhängigkeiten (einschließlich der transitiven) in requirements.txt für die App enthalten sein sollte, nicht in setup.py des Pakets. Dies umreißt die Idee, dass die Bereitstellung einer App nicht mit pip install myapp==1.0.0 erfolgt, sondern pip install -r requirements.txt (oder pipenv install mit Pipfile.lock ), wobei die requirements.txt enthält myapp==1.0.0 sowie alle anderen Abhängigkeiten und transitiven Abhängigkeiten, gepinnt.
Es sieht vielleicht so aus, als würde ich ein bisschen zu weit gehen, aber ich habe in einem Kontext gearbeitet, in dem die bereitgestellte „App“ von einer Reihe von Paketen gesteuert wird. Es gibt kein einziges Paket, das die App selbst darstellt, also wurde mir diese Vorstellung, dass „das Paket nicht die App ist“, ziemlich früh ins Gesicht geschmissen 😄 .

Ich habe das starke Gefühl, dass Pipenv/Pipfile/Pipfile.lock dieser Idee folgt.
Aus diesem Grund scheint es eine Lücke zu geben, um von Pipfile.lock zu setup.py 's install_requires zu wechseln: Es ist auf keinen Fall so gemeint.

@maintainers Ich hätte gerne Ihren Beitrag hier, um zu wissen, ob Sie das alles tatsächlich so sehen. Ich habe eine Vision davon gepredigt, wie wir mit Abhängigkeiten umgehen sollten, aber ich möchte auch nicht an Ihrer Stelle sprechen.

@vphilippon Ich denke, es gibt unterschiedliche Standpunkte und Terminologien. Aber letztendlich möchten wir, dass eine Liste mit fixierten Abhängigkeiten installiert wird. Ein requirements.txt mit gepinnten Versionen (oder ein Paket mit solchen deklarierten Abhängigkeiten, spielt also keine Rolle). Die Frage ist, wie erstellt man eigentlich eine solche Datei?

Mit pip-compile (von pip-tools ) kann ich ein solches requirements.txt aus requirements.in kompilieren und es enthält nur die Nicht-Entwickler-Abhängigkeiten, die meine App benötigt. Ich bin mir nicht sicher, ob ich Ihre Antwort richtig interpretiere - meinen Sie wirklich, dass wir angeheftete Abhängigkeiten requirements.txt von Hand beibehalten sollten (auch leicht duplizieren, was bereits in setup.py ), auch für transitive Abhängigkeiten? Das kann nicht die Lösung sein...

Wenn es pipenv lock --no-dev -r gäbe, würde das meiner Meinung nach dieses Problem lösen.

@tuukkamustonen Entschuldigung für die Verwirrung, ich habe wirklich nur die Idee von install_requires vs. requirements.txt / Pipfile / Pipfile.lock angesprochen.

Eine requirements.txt mit gepinnten Versionen (oder ein Paket mit solchen deklarierten Abhängigkeiten spielt also keine Rolle).

Ich denke, die Unterscheidung ist wirklich wichtig, aber wie Sie sagten, gibt es hier verschiedene Standpunkte. Lassen Sie uns vereinbaren, erst einmal nicht zuzustimmen. Als Randbemerkung wäre es schön, einen Ort zu haben, an dem man das Thema weiterverfolgen kann, ohne einem bestimmten Thema Lärm hinzuzufügen. Das ist die Art von Dingen, die meiner Meinung nach mehr Diskussionen und den Austausch in der Community erfordern.

Es scheint jedoch nicht so, als ob es pipenv erlaubt, Entwicklungsanforderungen in pipenv lock -r auszuschließen

Aber letztendlich möchten wir, dass eine Liste mit fixierten Abhängigkeiten installiert wird. [...] Die Frage ist, wie erstellt man eigentlich eine solche Datei? [...] Mit pip-compile (von pip-tools) kann ich eine solche requirements.txt aus requirements.in kompilieren und sie enthält nur die Nicht-Entwickler-Abhängigkeiten, die meine App benötigt.

Ah, diesen Teil habe ich zuerst übersprungen, sorry. Und es scheint, dass Sie Recht haben: Ich bin nicht in der Lage, einen Weg zu finden, pipenv install --not-dev-stuff zu sagen (ich war mir ziemlich sicher, dass es einen gab, seltsam) und eine Nicht-Entwicklungsumgebung zu generieren. Was bringt es dann, zwei getrennte Abschnitte zu haben? Dann fehlt mir vielleicht etwas, und das hat nichts mit der Verwendung mit setup.py zu tun. Vielleicht lohnt es sich, in einer neuen Ausgabe darüber zu diskutieren.

BEARBEITEN:
Ich habe hier einen Fehler gemacht. Ich habe in der Tat keinen Weg gefunden, ein Pipfile.lock ohne Dev-Pakete zu generieren, aber in einer neuen Umgebung mit vorhandenen Pipfile / Pipfile.lock pipenv install zu machen installiert die dev-Pakete nicht. Dies löst nicht den Punkt von @tuukkamustonen , aber ich habe mich geirrt, als ich sagte, dass es keine Möglichkeit gibt, eine "prod-Umgebung" zu installieren, mein Fehler.

Puh, das war viel nachzuholen.

Wenn ich mich nicht stark irre, kann der Code in #209 (Kommentar) sicher verwendet werden, wenn Sie ein Rad bauen (= binäre Distanz), aber nicht, wenn Sie sdist (= Quellendistanz) bauen.

@tuukkamustonen Dies ist nur für die Verwendung in einem eigenständigen Skript für Bereitstellungen vorgesehen, fügen Sie es nicht in Ihre setup.py ein. Dies ist ein halbwegs hackiger Workaround aus der Zeit, bevor wir vor vielen Monaten pipenv lock -r hatten. Dieser Ansatz funktioniert jedoch für Ihren Anwendungsfall der Aufteilung von packages und dev-packages .

Ich persönlich verwende (3) (siehe Nr. 209 (Kommentar)), bis Pipfile mehr zu einem gemeinsamen Standard wird. An diesem Punkt werde ich keines meiner Projekte mehr direkt von Pipenv-Code abhängig machen, da Pipenv eindeutig dazu gedacht zu sein scheint Tool zum Verwalten einer virtuellen Umgebung basierend auf einem Pipfile und nicht unbedingt einer Pipfile-Bibliothek selbst.

@elgertam Es scheint, dass Ihre Meinung seit diesem Kommentar beeinflusst wurde, aber ich möchte anmerken, dass es wahrscheinlich keine gute Idee ist, pipenv mit Ihrem Projekt zu bündeln. Es gibt nichts, was dies ausdrücklich verbietet, aber wir führen eine Menge Pfad-Patching durch, was dazu neigt, Probleme zu verursachen, wenn es so verwendet wird. Ich denke, ich werde dies nur mit einer Warnung "Verwendung auf eigene Gefahr" umschließen.

Betreuer Ich hätte gerne Ihren Beitrag hier, um zu wissen, ob Sie das alles tatsächlich so sehen. Ich habe eine Vision davon gepredigt, wie wir mit Abhängigkeiten umgehen sollten, aber ich möchte auch nicht an Ihrer Stelle sprechen.

Ich denke, Sie entsprechen ziemlich gut unserer Vision für die Dauer des Projekts. Danke, dass du das alles zusammengestellt und so gut artikuliert hast @vphilippon!

Es sieht so aus, als ob die anderen relevanten Teile dieser Diskussion in #942 verschoben wurden, also denke ich, dass wir hier gut sind. Bitte pingen Sie mich an, wenn ich nichts angesprochen habe.

Ich folgte mit einem konkreten Vorschlag in https://github.com/pypa/pipfile/issues/98 , von dem ich glaube, dass er uns etwas umsetzbares und pragmatisches gibt, das DX für die Wartung von Python-Bibliotheken verbessern könnte.

Gedanken?

import json, jmespath

install_requires = []
with open('Pipfile.lock') as f:
    context = json.loads(f.read())
    install_requires.extend(map(
        lambda n, v : n + v,
        jmespath.search('default | keys(@)', context),
        jmespath.search('default.*.version', context),
    ))

setup(
    name='foobar',
    packages=find_packages(),
    setup_requires=['jmespath'],
    install_requires=install_requires,
)

@cornfeedhobo Mein Verständnis ist, dass setup_requires nicht gut mit Pip spielt. Könnten Sie ein wenig erläutern, wie Sie dieses Beispiel verwenden würden?

Das Beispiel funktioniert nur, wenn Sie jmespath zuerst installieren, da setup.py als normaler Python-Code ausgewertet wird. Das setup_requires -Argument bringt eigentlich nichts: Wenn das Programm so weit kommt, wird garantiert jmespath installiert.

Ich habe dies in einer anderen Ausgabe erwähnt, kann es aber nicht finden (es gibt so viele doppelte Diskussionen im gesamten Issue-Tracker, dass es unmöglich ist, etwas mehr zu finden), also sage ich es noch einmal: Bitte stellen Sie nichts, was nicht gebaut ist. in setup.py, es sei denn, Sie bieten einen geeigneten Fallback oder haben einen perfekten Grund. Ein Paket, das das obige setup.py enthält, funktioniert nicht einmal mit Pipenv, wenn jmespath in der virtuellen Umgebung installiert ist; Pipenv ruft setup.py egg_info in einer sauberen Umgebung auf und kann den jmespath-Import nicht ausführen. Das ist schlechte Praxis. Bitte vermeiden Sie es.

@epot das war mir nicht bewusst

@uranusjr Danke für die gut durchdachte Antwort mit Details. Ich untersuche gerade dieses ganze Thema, also könnte ich für mehr Verlegenheit zurückkehren. Ich verfolge auch pypa/pipfile#98

Was ist, wenn wir jmespath nicht benötigen?

import json


install_requires = []
tests_require = []

with open('Pipfile.lock') as fd:
    lock_data = json.load(fd)
    install_requires = [
        package_name + package_data['version']
        for package_name, package_data in lock_data['default'].items()
    ]
    tests_require = [
        package_name + package_data['version']
        for package_name, package_data in lock_data['develop'].items()
    ]

@mschwager Sie möchten die Version nicht anheften, oder die Benutzer werden eine schwierige Zeit haben. #1921 ist ein Beispiel für eine Bibliothek, die == verwendet, um den Build eines Benutzers zu beschädigen.

Ich entschuldige mich, aber was ist der Unterschied zwischen der Verwendung setup.py , um es als Paket zu verwenden, oder requirements.txt / Pipfile , um Abhängigkeiten dieses Pakets zu verwalten? Die erforderlichen Bibliotheken MÜSSEN zwischen setup.py und requirements.txt / Pipfile identisch sein, richtig? Daher gibt es keinen Grund, Pipfile nicht zu integrieren. setup.py analysiert bereits requirements.txt . Warum sollte es Pipfile nicht parsen können?

Wäre toll, requirements.txt loszuwerden und einfach Pipfile zu verwenden

Nein, es gibt keinen Grund, warum sie identisch sein _müssen_. Das ist eine ziemlich radikale Annahme, und viele in der Community würden das anders sehen.

Es gibt jedoch tatsächlich Gründe, warum sie identisch sein _können_. Pipenv schließt das nicht aus. Es ist einfach außerhalb des Geltungsbereichs und wird von diesem Projekt nicht unterstützt. Sie können eine Bibliothek erstellen, um dies vollständig zu unterstützen, und PEP 518 nutzen, das in pip 10.0 implementiert ist, um Build-Time-Unterstützung bereitzustellen.

Wie Sie sagten, gibt es keinen Grund, setup.py nicht zu erlauben, Pipfile zu analysieren. Ich freue mich darauf, dass du das schaffst :)

Verstehst du, dass einige Leute die abstrakten Bibliotheken von setup.py mögen, aber das ist kein Muss? Ich meine, Golang leidet darunter, nur konkrete Anforderungen zu haben, aber trotzdem in der Lage zu sein, eine erforderliche Bibliothek durch Ihre eigene Gabel zu ersetzen, nur weil sie zum Namen passt? Verständlich, dass die setup.py-Intergation einfach nicht im Geltungsbereich liegt.

Es wäre jedoch interessant zu sehen, wie die langfristige Roadmap von pipenv aussieht. Wäre toll zu sehen, dass es das Go-to-Tool in Python wird. Ersetzt zB irgendwie setup.py oder generiert eine geeignete setup.py für den Benutzer, so oder so ist es großartig, dass pipenv de facto ein Paketmanager ist. Ich frage mich nur, ob es eine Möglichkeit gibt, den Umfang um setup.py zu erweitern?

Wenn pipenv wie npm usw. ist, dann erlaubt ihr package.json eine Remote-Installation, kein Grund, dass pipenv nicht mit setup.py interagieren oder es ersetzen kann, wodurch es in den Geltungsbereich gelangt. Mache ich Sinn oder klingt es, als würde ich verrückte Pillen nehmen?

Vielen Dank, dass Sie denken, dass es ein Muss ist. Da Sie es für so wichtig halten, glaube ich, dass wir in kürzester Zeit ein Pipfile-basiertes Build-System ausführen können.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen