Anforderungen.txt vs setup.py

109

Ich begann mit Python zu arbeiten. Ich habe requirements.txtund setup.pyzu meinem Projekt hinzugefügt . Aber ich bin immer noch verwirrt über den Zweck beider Dateien. Ich habe gelesen, dass dies setup.pyfür weiterverteilbare Dinge und requirements.txtfür nicht weiterverteilbare Dinge ausgelegt ist. Ich bin mir jedoch nicht sicher, ob dies korrekt ist.

Wie sollen diese beiden Dateien wirklich verwendet werden?

Lucy
quelle
1
Haben Sie das Web mit Ihrem genauen Titel durchsucht? Dieser Artikel (der erste Treffer bei der Suche) ist der beste, den ich zu diesem Thema gelesen habe.
Chris
2
Dieser Artikel könnte nützlich sein: caremad.io/posts/2013/07/setup-vs-requirement (Entschuldigung, zu faul, um das Wesentliche in eine richtige Antwort zu extrahieren). Eine andere Sache ist, dass einige Tools (z. B. das Testen) ihre Vorurteile gegenüber dem einen oder anderen haben können - aber lassen Sie sich nicht stören, wenn Sie gerade mit der Arbeit an Python begonnen haben.
Drdaeman

Antworten:

81

Anforderungen.txt

Dies hilft Ihnen beim Einrichten Ihrer Entwicklungsumgebung. Programme wie pipkönnen verwendet werden, um alle in der Datei aufgelisteten Pakete auf einen Schlag zu installieren. Danach können Sie mit der Entwicklung Ihres Python-Skripts beginnen. Besonders nützlich, wenn Sie vorhaben, dass andere zur Entwicklung beitragen oder virtuelle Umgebungen verwenden. So verwenden Sie es:

pip install -r requirements.txt

setup.py

Auf diese Weise können Sie Pakete erstellen, die Sie neu verteilen können. Dieses Skript soll Ihr Paket auf dem System des Endbenutzers installieren und die Entwicklungsumgebung nicht wie gewohnt vorbereiten pip install -r requirements.txt. Weitere Informationen zu setup.py finden Sie in dieser Antwort .

Die Abhängigkeiten Ihres Projekts sind in beiden Dateien aufgeführt.

AndreasT
quelle
2
In welchen Fällen hätte ich nur einen davon? In welchem ​​hätte ich beides?
Martin Thoma
25
Ähm ... Sie schreiben nur zum Spaß auf Ihrem lokalen Computer: Weder noch. Das Skript wurde auf mehreren Computern / Vitualen entwickelt, aber nicht neu verteilt: require.txt. Das Skript wird nur auf Ihrem Computer entwickelt, sollte jedoch neu verteilt werden: setup.py. Das Skript wird in mehreren Umgebungen neu verteilt und entwickelt: Beide.
AndreasT
Könnten Sie dies der Antwort hinzufügen?
Martin Thoma
57

Die kurze Antwort lautet, dass requirements.txtnur die Paketanforderungen aufgelistet werden. setup.pyAuf der anderen Seite ähnelt es eher einem Installationsskript. Wenn Sie nicht vorhaben, den Python-Code zu installieren, benötigen Sie normalerweise nur requirements.txt.

Die Datei setup.pybeschreibt zusätzlich zu den Paketabhängigkeiten die Gruppe von Dateien und Modulen, die gepackt (oder kompiliert werden sollen, im Fall von nativen Modulen (dh in C geschrieben)) und Metadaten, die zu den Python-Paketlisten hinzugefügt werden sollen ( zB Paketname, Paketversion, Paketbeschreibung, Autor, ...).

Da in beiden Dateien Abhängigkeiten aufgeführt sind, kann dies zu einer gewissen Duplizierung führen. Lesen Sie unten für Details.

Anforderungen.txt


Diese Datei listet die Anforderungen für Python-Pakete auf. Es ist eine einfache Textdatei (optional mit Kommentaren) , dass die Listen der Paketabhängigkeiten Ihrer Python - Projekt (eine pro Zeile). Es wird nicht beschrieben, wie Ihr Python-Paket installiert wird. Sie würden in der Regel die Anforderungsdatei mit verbrauchen pip install -r requirements.txt.

Der Dateiname der Textdatei ist willkürlich, wird jedoch häufig requirements.txtdurch Konvention festgelegt. Wenn Sie Quellcode-Repositorys anderer Python-Pakete durchsuchen, stoßen Sie möglicherweise auf andere Namen wie dev-dependencies.txtoder dependencies-dev.txt. Diese dienen demselben Zweck wie dependencies.txtzusätzliche Abhängigkeiten, die für Entwickler des jeweiligen Pakets von Interesse sind, jedoch im Allgemeinen, um den Quellcode (z. B. Pytest, Pylint usw.) vor der Veröffentlichung zu testen. Benutzer des Pakets benötigen im Allgemeinen nicht den gesamten Satz von Entwicklerabhängigkeiten, um das Paket auszuführen.

Wenn mehrere requirements-X.txtVarianten vorhanden sind, listet normalerweise eine Laufzeitabhängigkeiten und die andere Build-Time- oder Testabhängigkeit auf. Einige Projekte kaskadieren auch ihre Anforderungsdatei, dh wenn eine Anforderungsdatei eine andere Datei enthält ( Beispiel ). Dies kann die Wiederholung verringern.

setup.py


Dies ist ein Python-Skript, das das setuptoolsModul verwendet, um ein Python-Paket zu definieren (Name, enthaltene Dateien, Paketmetadaten und Installation). Es werden requirements.txtauch Laufzeitabhängigkeiten des Pakets aufgelistet. Setuptools ist die de-facto-Methode zum Erstellen und Installieren von Python-Paketen, weist jedoch Mängel auf, die im Laufe der Zeit zur Entwicklung neuer "Meta-Paket-Manager" wie pip geführt haben. Beispielhafte Mängel von setuptools sind die Unfähigkeit, mehrere Versionen desselben Pakets zu installieren, und das Fehlen eines Deinstallationsbefehls.

Wenn ein Python-Benutzer dies tut pip install ./pkgdir_my_module(oder pip install my-module), wird pip setup.pyin dem angegebenen Verzeichnis (oder Modul) ausgeführt. In ähnlicher Weise , die jedes Modul eine hat setup.pykann pipdurch Ausführen -Installierte, zB pip install .aus dem gleichen Ordner.

Brauche ich wirklich beides


Kurze Antwort ist nein, aber es ist schön, beides zu haben. Sie erfüllen unterschiedliche Zwecke, können jedoch beide zum Auflisten Ihrer Abhängigkeiten verwendet werden.

Es gibt einen Trick, den Sie in Betracht ziehen können, um zu vermeiden, dass Ihre Abhängigkeitsliste zwischen requirements.txtund dupliziert wird setup.py. Wenn Sie bereits ein voll funktionsfähiges setup.pyPaket für Ihr Paket geschrieben haben und Ihre Abhängigkeiten größtenteils extern sind, können Sie ein einfaches requirements.txtmit nur den folgenden Optionen in Betracht ziehen :

 # requirements.txt
 #
 # installs dependencies from ./setup.py, and the package itself,
 # in editable mode
 -e .

 # (the -e above is optional). you could also just install the package
 # normally with just the line below (after uncommenting)
 # .

Dies -eist eine spezielle pip installOption, mit der das angegebene Paket im bearbeitbaren Modus installiert wird . Wenn pip -r requirements.txtdiese Datei ausgeführt wird, installiert pip Ihre Abhängigkeiten über die Liste in ./setup.py. Die bearbeitbare Option platziert einen Symlink in Ihrem Installationsverzeichnis (anstelle eines Eies oder einer archivierten Kopie). Entwickler können damit Code aus dem Repository bearbeiten, ohne ihn neu installieren zu müssen.

Sie können auch die sogenannten "Setuptools-Extras" nutzen, wenn Sie beide Dateien in Ihrem Paket-Repository haben. Sie können optionale Pakete in setup.py unter einer benutzerdefinierten Kategorie definieren und diese Pakete aus nur dieser Kategorie mit pip installieren:

# setup.py
from setuptools import setup
setup(
   name="FOO"
   ...
   extras_require = {
       'dev': ['pylint'],
       'build': ['requests']
   }
   ...
)

und dann in der Anforderungsdatei:

# install packages in the [build] category, from setup.py
# (path/to/mypkg is the directory where setup.py is)
-e path/to/mypkg[build]

Dies würde alle Ihre Abhängigkeitslisten in setup.py behalten.

Hinweis : Normalerweise führen Sie pip und setup.py in einer Sandbox aus, z. B. mit dem Programm virtualenv. Dadurch wird vermieden, dass Python-Pakete außerhalb des Kontexts der Entwicklungsumgebung Ihres Projekts installiert werden.

init_js
quelle
7
und Sie können auch nur haben .w / o -einnen requirements.txt. Diese Methode delegiert nur alle Anforderungen an setup.pyund Sie müssen niemanden in den bearbeitbaren Modus zwingen. Benutzer können weiterhin tun, pip install -e .wenn sie möchten.
Stason
1
Interessanter Trick mit "-e". in den Anforderungen.txt, aber macht das nicht den Zweck zunichte, dass die Anforderungen.txt die genauen Systemspezifikationen sind? Warum in diesem Fall überhaupt einen haben?
Ben Ogorek
Die genauen Systemanforderungen finden Sie in setup.py. Mit "." In require.txt wird die Datei setup.py im aktuellen Ordner verwendet. Die Verwendung -e .verwendet auch setup.py, um Abhängigkeiten zu finden, verknüpft jedoch den aktuellen Ordner (an Ort und Stelle mit einem Symlink) im Ordner pip install, anstatt eine Kopie zu -eerstellen. Dies wird im Allgemeinen nur verwendet, wenn Sie das Paket entwickeln. Mit -ewerden Änderungen an Ihren Python-Paketdateien (* .py) sofort in Ihrer Pip-Umgebung wirksam, anstatt die Neuinstallation des Pakets nach jeder Änderung erzwingen zu müssen.
init_js
@init_js ist der "aktuelle Ordner" relativ zur Anforderungsdatei oder CWD, von der pip aufgerufen wird? Dh wenn Sie dies tun, cd foo && pip install -r ./bar/requirements.txtwird in foo/baroder nach setup.py gesucht foo? Wenn letzteres der Fall ist, gibt es einen Weg, das erstere zu erreichen?
Dan M.
pip -r REQkümmert sich nicht um das Verzeichnis, in dem sich REQ befindet. Sie können es von einem Fifo füttern, auch wenn Sie möchten : pip install -r <(echo "mylib1"; echo "mylib2";). Wo <(CMD)ist die Bash-Befehlsersetzung, nicht die Standardumleitung?
init_js
12

Der Vollständigkeit halber sehe ich es hier in 3 4 verschiedenen Winkeln.

  1. Ihre Designzwecke sind unterschiedlich

Dies ist die genaue Beschreibung aus der offiziellen Dokumentation (Schwerpunkt Mine):

Während install_requires (in setup.py) die Abhängigkeiten für ein einzelnes Projekt definiert , werden Anforderungsdateien häufig verwendet, um die Anforderungen für eine vollständige Python-Umgebung zu definieren .

Während die Anforderungen für install_requires minimal sind, enthalten Anforderungsdateien häufig eine vollständige Liste der angehefteten Versionen, um wiederholbare Installationen einer vollständigen Umgebung zu erreichen.

Es ist jedoch möglicherweise immer noch nicht leicht zu verstehen. Im nächsten Abschnitt werden zwei sachliche Beispiele aufgeführt, um zu demonstrieren, wie die beiden Ansätze unterschiedlich verwendet werden sollen.

  1. Ihre tatsächlichen Verwendungen sind daher (sollen) unterschiedlich

    • Wenn Ihr Projekt fooals eigenständige Bibliothek veröffentlicht werden soll (was wahrscheinlich andere tun würden import foo), möchten Sie (und Ihre nachgeschalteten Benutzer) eine flexible Abhängigkeitserklärung haben, damit Ihre Bibliothek dies nicht tut (und dies auch nicht muss) ) Seien Sie "wählerisch", wie genau Ihre Abhängigkeiten aussehen sollen. Normalerweise enthält Ihre setup.py folgende Zeilen:

      install_requires=[
          'A>=1,<2',
          'B>=2'
      ]
    • Wenn Sie Ihre EXAKTE aktuelle Umgebung für Ihre Anwendung nur irgendwie "dokumentieren" oder "anheften" möchten bar, dh Sie oder Ihre Benutzer möchten Ihre Anwendung barunverändert verwenden, dh ausführen python bar.py, möchten Sie möglicherweise Ihre Umgebung einfrieren, damit sie einfriert würde sich immer gleich verhalten. In diesem Fall würde Ihre Anforderungsdatei folgendermaßen aussehen:

      A==1.2.3
      B==2.3.4
      # It could even contain some dependencies NOT strickly required by your library
      pylint==3.4.5
  2. Welches verwende ich in Wirklichkeit?

    • Wenn Sie eine Anwendung entwickeln, bardie von verwendet wird python bar.py, auch wenn dies "nur zum Spaß ein Skript" ist, wird Ihnen dennoch empfohlen, die Datei "resources.txt" zu verwenden, da Sie, wer weiß, nächste Woche (was zufällig Weihnachten ist) eine erhalten würden neuer Computer als Geschenk, daher müssten Sie dort Ihre genaue Umgebung erneut einrichten.

    • Wenn Sie eine Bibliothek entwickeln, foodie von verwendet wird import foo, müssen Sie eine setup.py vorbereiten. Zeitraum. Sie können sich jedoch auch dafür entscheiden, gleichzeitig eine require.txt bereitzustellen, die Folgendes kann:

      (a) entweder im A==1.2.3Stil sein (wie in # 2 oben erklärt);

      (b) oder nur eine magische Single enthalten .

      .

      Dies würde in etwa "Installieren der Anforderungen basierend auf setup.py" ohne Duplizierung bedeuten. Persönlich denke ich, dass dieser letzte Ansatz die Linie verwischt, die Verwirrung erhöht und NICHT wirklich einen Mehrwert schafft, aber dennoch ein Trick ist, der aus einem Ansatz abgeleitet wurde, den Python-Verpackungsbetreuer Donald in seinem Blogbeitrag erwähnt hat .

  3. Unterschiedliche Untergrenzen.

    Selbst nachdem Sie die oben genannten 3 Kriterien befolgt und richtig entschieden haben, dass Ihre Bibliothek a hybrid-engineverwendet setup.py, um ihre Abhängigkeit zu deklarieren engine>=1.2.0, und Ihre Beispielanwendung reliable-carverwendet requirements.txt, um ihre Abhängigkeit zu deklarieren engine>=1.2.3, obwohl die neueste Version von enginebereits 1.4.0 ist. Wie Sie sehen, unterscheidet sich Ihre Wahl für die Anzahl der unteren Grenzen immer noch geringfügig. Und hier ist warum.

    • hybrid-enginehängt davon ab engine>=1.2.0, dass hypothetisch gesehen die erforderliche Fähigkeit zur "internen Verbrennung" erstmals eingeführt engine 1.2.0wurde und diese Fähigkeit die Notwendigkeit ist hybrid-engine, unabhängig davon, ob in einer solchen Version einige (geringfügige) Fehler vorhanden sind und in nachfolgenden Versionen 1.2.1 behoben wurden , 1.2.2 und 1.2.3.

    • reliable-carhängt davon ab, engine>=1.2.3da dies die früheste Version OHNE bekannte Probleme ist. Sicher, in späteren Versionen gibt es neue Funktionen, z. B. "Elektromotor" engine 1.3.0und "Kernreaktor" engine 1.4.0, aber sie sind für das Projekt nicht erforderlich reliable-car.

RayLuo
quelle
"Ihre Bibliothek würde (und darf auch nicht) wählerisch sein, welche genaue Version IHRER Abhängigkeiten sein sollte." Könnten Sie diesen Punkt etwas näher erläutern? Ich denke, Ihr Code wird normalerweise nur mit bestimmten Versionen von Abhängigkeiten getestet, und dieser Ansatz kann etwas gefährlich sein. Ich gehe davon aus, dass eine Bibliothek mit einer Reihe von Versionen funktionieren sollte, da Sie nicht zu viele Versionen von Abhängigkeiten installieren möchten. Speicherplatz sparen?
Taro Kiritani
@TaroKiritani Eigentlich habe ich zwei verschiedene Szenarien nebeneinander aufgelistet, den Bibliotheksfall und den Anwendungsfall. Vielleicht haben Sie vorher nicht an einer Bibliothek gearbeitet? Als Bibliothek wird erwartet, dass sie von nachgeschalteten Paketen verwendet wird. Wenn Sie also wählerisch sind, IHRE Abhängigkeit zu bestimmen A==1.2.3, und wenn das Downstream-Paket Ihrer Bibliothek davon abhängt A==1.2.4, gibt es jetzt keine Möglichkeit, beide zu erfüllen. Die Lösung zur Minimierung dieses Konflikts besteht darin, dass Ihre Bibliothek einen Bereich definiert, von dem Sie wissen, dass er funktionieren würde. Angenommen, viele Upstream-Bibliotheken folgen bereits semver.org , A>=1,<2würde funktionieren.
RayLuo
Ich wusste nicht, dass nur eine Version eines Pakets in einer einzigen Umgebung installiert werden kann. stackoverflow.com/a/6572017/5686692 Vielen Dank für die Klarstellung.
Taro Kiritani
1
@TaroKiritani, ja, sonst wie würden Sie Ihre App wissen , welche Version von foonicht import fooIhnen geben? Diese hackig akzeptierten Antworten in dem von Ihnen angegebenen Link sind ein perfektes Beispiel dafür, warum Paketbetreuer "nicht wählerisch sein sollten und dürfen". :-) Darf ich jetzt deine Gegenstimme haben?
RayLuo
1
Ich könnte diesen neuen Gedanken auch kommentieren, aber dann geht dieser Kommentarbereich bereits vom Thema ab und ist für Neuankömmlinge schwer zu folgen. Ich würde vorschlagen, dass Sie eine neue Frage stellen: "Sollen wir Tox oder etwas verwenden, um
sicherzustellen