Hallo Christopher und andere :-) ich starte hier einen neuen Thread, denn das hat mit dem alten nicht mehr viel zu tun. Ich verstehe nicht so richtig warum dieser Ablauf von pip-tools[1] verwendet wird. Ich sehe das so: in setup.py install_requires sind die ungenauen Abhängigkeiten eingetragen (kein Pinning). Dann läuft das CI und wenn alles ok ist, dann wird eine req.txt per "pip freeze" erstellt. Dies erstelle req.txt enthält dann das Ergebnis des CI: dieser Stand (alles version-pinned) ist erfolgreich getestet worden. Sicherlich funktioniert das alles mit pip-compile .... irgendwie ist es eine endlose Quelle von Verwirrungen, dass es in der Python Welt zwei Wege für die Definition von Abhängigkeiten gibt (setup.py/install_requires und req.txt). Warum sollte man mit den pip-tools die req.txt Dateien aktualisieren? [1] https://github.com/jazzband/pip-tools -- Thomas Guettler http://www.thomas-guettler.de/
Hallo Thomas und andere Interessierte, Am 23.03.2017 um 12:07 schrieb Thomas Güttler:
Ich verstehe nicht so richtig warum dieser Ablauf von pip-tools[1] verwendet wird.
ich fange mal mit einer allgemeinen Antwort auf deine letzte Frage an:
Warum sollte man mit den pip-tools die req.txt Dateien aktualisieren?
* Es müssen in den Eingabe-Dateien nur idR die direkten Abhängigkeiten definiert werden. * Die erzeugten Requirements-Dateien pinnen direkte und indirekte Abhängigkeiten. * Beim Erstellen der Requirements wird sichergestellt, dass die gepinnten Versionen auch verfügbar sind, ... * ... und dass der geforderte Abhängigkeitsgraph auflösbar ist, ... * und dies auch bei Requirements-Dateien, die von einander abhängen, z.B. 'production.txt'->'base.txt' und 'dev.txt'->'base.txt' * Man kann die geforderten Versionen einzelner Dependencies ändern, ohne dass das unbeabsichtige Änderungen bei anderen Abhängigkeiten hat.
Ich sehe das so: in setup.py install_requires sind die ungenauen Abhängigkeiten eingetragen (kein Pinning).
irgendwie ist es eine endlose Quelle von Verwirrungen, dass es in der Python Welt zwei Wege für die Definition von Abhängigkeiten gibt (setup.py/install_requires und req.txt).
"ungenauen" ist etwas ungenau :) In den "install_requires" werden die abstrakten Abhängigkeiten festgelegt, die die Software braucht. D.h. hier dürfen idR keine festen Versionen gepinnt werden (!) sondern höchstens Mindestversionen und u.U. Maximalversionen der Abhängigkeiten. Die install_requires werden verwendet, wenn aus der Software ein (TGZ, Wheel, Egg)-Paket gebaut wird und dieses dann via easy_install oder pip installiert wird. Hast du nun eine Anwendung X, und diese will Paket A und B installieren, und Paket A hat in seiner setup.py stehen 'install_requires = ["C==1.0"]' und Paket B hat in seiner setup.py stehen 'install_requires = ["C==2.0"]' kommmt es zu einem Versionskonflikt: die Abhängigkeiten deiner Software lassen sich nicht mehr installieren. In den Requirements-Dateien dagegen stehen nicht die Abhängigkeiten deiner Anwendung, sondern eine mögliche Lösung des Abhängigkeitsgraphen. Diese stellt eine Beschreibung der Python-Umgebung für deine Anwedung dar (Pythonversion, Rechner-Architektur, und OS jetzt mal außen vor gelassen). Dieser Stand wird installiert, gegen diesen laufen die Tests und diesen will man auf dem Produktionssystem gleichermaßen herstellen. Das heisst, in den Requierements-Dateien will ich die genauen Versionen aller Abhängigkeiten pinnen, denn nur für diese ist getestet, dass sie sich alle gemeinsam installieren lassen und nur gegen diese sind die Ergebnisse der Tests valide.
Dann läuft das CI und wenn alles ok ist, dann wird eine req.txt per "pip freeze" erstellt. Dies erstelle req.txt enthält dann das Ergebnis des CI: dieser Stand (alles version-pinned) ist erfolgreich getestet worden.
Ja, aber wenn du dann die Version einer Dependency aktualisieren willst, was machst du dann? * Trage ich die neue Version einfach in die Requierements-Datei ein, ist nicht sichergestellt, dass sich die neue Version überhaupt mit den sonstigen Versionen, die in der Requirementsdate gepinnt sind, installieren lässt. * Installiere ich die neue Version einfach mit "pip install -U XYZ", werden höchstwahrscheinlich weitere Abhängkeiten aktuaisiert und es findet keine Prüfung statt, ob deren neue Versionen mit meiner Anwendung kompatibel sind. Wo sollte eine solche Einschränkung dokumentiert werden? * Installiere ich die neue Version mit "pip install -U --no-deps XYZ", bekommme ich mit einem "pip freeze" danach einen Stand meiner Umgebung, der sich u.U. gar nicht mehr mit "pip install -r requirements.txt" installieren lässt, weil die gepinnten Versionen nicht mehr zum Abhängigkeitsgraphen passen. Mit pip-tools erhöhe ich einfach die Mindestversion der Abhängigkeit in der requirements.in Datei, lasse dann nochmal pip-compile laufen und habe danach eine valide requirements.txt Datei oder bekomme eben gleich einen Fehler und weiß, dass die Abhängigkeiten nicht zusammen passen (und nicht erst, wenn versucht wird, "pip install -r ..." im CI oder gar erst auf dem Staging/Produktionssystem auszuführen). Ich hoffe, ich habe die Problematik damit etwas verdeutlichen können. Hier noch der Link zu einem interessanten Blog-Artikel über einen guten Workflow für pip-tools: http://jamescooke.info/a-successful-pip-tools-workflow-for-managing-python-p... Diesen habe ich hier (mit einigen kleinen Anpassungen) umgesetzt: https://github.com/SpotlightKid/python-package-cookiecutter/blob/master/%7B%... Chris
Am 24.03.2017 um 20:20 schrieb Christopher Arndt:
Hallo Thomas und andere Interessierte,
Am 23.03.2017 um 12:07 schrieb Thomas Güttler:
Ich verstehe nicht so richtig warum dieser Ablauf von pip-tools[1] verwendet wird.
ich fange mal mit einer allgemeinen Antwort auf deine letzte Frage an:
Warum sollte man mit den pip-tools die req.txt Dateien aktualisieren?
* Es müssen in den Eingabe-Dateien nur idR die direkten Abhängigkeiten definiert werden. * Die erzeugten Requirements-Dateien pinnen direkte und indirekte Abhängigkeiten. * Beim Erstellen der Requirements wird sichergestellt, dass die gepinnten Versionen auch verfügbar sind, ... * ... und dass der geforderte Abhängigkeitsgraph auflösbar ist, ... * und dies auch bei Requirements-Dateien, die von einander abhängen, z.B. 'production.txt'->'base.txt' und 'dev.txt'->'base.txt' * Man kann die geforderten Versionen einzelner Dependencies ändern, ohne dass das unbeabsichtige Änderungen bei anderen Abhängigkeiten hat.
Ich sehe das so: in setup.py install_requires sind die ungenauen Abhängigkeiten eingetragen (kein Pinning).
irgendwie ist es eine endlose Quelle von Verwirrungen, dass es in der Python Welt zwei Wege für die Definition von Abhängigkeiten gibt (setup.py/install_requires und req.txt).
"ungenauen" ist etwas ungenau :) In den "install_requires" werden die abstrakten Abhängigkeiten festgelegt, die die Software braucht. D.h. hier dürfen idR keine festen Versionen gepinnt werden (!) sondern höchstens Mindestversionen und u.U. Maximalversionen der Abhängigkeiten.
ok. Hier sind wir 100% einer Meinung. Genau das meinte ich mit "ungenau".
Die install_requires werden verwendet, wenn aus der Software ein (TGZ, Wheel, Egg)-Paket gebaut wird und dieses dann via easy_install oder pip installiert wird. Hast du nun eine Anwendung X, und diese will Paket A und B installieren, und Paket A hat in seiner setup.py stehen 'install_requires = ["C==1.0"]' und Paket B hat in seiner setup.py stehen 'install_requires = ["C==2.0"]' kommmt es zu einem Versionskonflikt: die Abhängigkeiten deiner Software lassen sich nicht mehr installieren.
In den Requirements-Dateien dagegen stehen nicht die Abhängigkeiten deiner Anwendung, sondern eine mögliche Lösung des Abhängigkeitsgraphen. Diese stellt eine Beschreibung der Python-Umgebung für deine Anwedung dar (Pythonversion, Rechner-Architektur, und OS jetzt mal außen vor gelassen). Dieser Stand wird installiert, gegen diesen laufen die Tests und diesen will man auf dem Produktionssystem gleichermaßen herstellen. Das heisst, in den Requierements-Dateien will ich die genauen Versionen aller Abhängigkeiten pinnen, denn nur für diese ist getestet, dass sie sich alle gemeinsam installieren lassen und nur gegen diese sind die Ergebnisse der Tests valide.
Ja, genau. Die req.txt ist einen Lösung des Abhängigkeitsgraphen.
Dann läuft das CI und wenn alles ok ist, dann wird eine req.txt per "pip freeze" erstellt. Dies erstelle req.txt enthält dann das Ergebnis des CI: dieser Stand (alles version-pinned) ist erfolgreich getestet worden.
Ja, aber wenn du dann die Version einer Dependency aktualisieren willst, was machst du dann?
Das erhöhen der Version einer Dependency mache ich ja nicht aus Spaß an der Freude. Dafür gibt es Gründe. Ich passe das Modul an, dass die höhere Version braucht. Wie ich das mache? Ich erhöhe die >= Angabe von der install_requires-Zeile in setup.py Für mich sollte req.txt nur das Ergebnis von CI sein. Ich stelle mir mal diesen Graph vor: ProjektFoo -> libbar -> libsub Wenn etwas in ProjektFoo schief geht, weil libsub noch in Version 0.1 ist, und es in Version 0.2 klappt. Dann steht man vor der Frage: Was tun? Das ist dann abzuwägen. Strategie1: libbar Abhängigkeit erhöhen. Strategie2: ProjektFoo bekommt eine Abhängigkeit zu libsub. Aus meiner Sicht sind beide Wege plausibel. Das ist im Einzelfall zu betrachten. Ich bin großer Freund von zwei Dingen, die super langweilig und nahezu narkotisierend einschläfernd wirken: SQL und EVA Mit EVA meine ich: Eingabe-Verarbeitung-Ausgabe. Meine Sichtweise: Eingabe für das CI ist install_requires aus setup.py Dann kommt die Vearbeitung im CI. Dann kommt das Ergebnis: Fall1: Mindestens ein Test ist fehlgeschlagen. Fall2: Alles prima: req.txt wurde erstellt. Mit dieser Liste von Software klappt es. Im ehrlich zu sein ist bei uns derzeit im Input auch eine req.txt Datei. Das ist aber nur weil so weit ich weiß in install_requires nicht ein "git+https://..." stehen kann.
* Trage ich die neue Version einfach in die Requierements-Datei ein, ist nicht sichergestellt, dass sich die neue Version überhaupt mit den sonstigen Versionen, die in der Requirementsdate gepinnt sind, installieren lässt.
Ich wüsste nicht warum ich in Requirements-Datei per Hand Änderungen machen sollte.
* Installiere ich die neue Version einfach mit "pip install -U XYZ", werden höchstwahrscheinlich weitere Abhängkeiten aktuaisiert und es findet keine Prüfung statt, ob deren neue Versionen mit meiner Anwendung kompatibel sind. Wo sollte eine solche Einschränkung dokumentiert werden?
Sicherlich kann man im Entwicklungssystem "pip install -U xyz" machen. Aber wo wird das Ergebnis notiert? Es wird ja nur die virtualenv angepasst. Wenn ich danach "git diff" auf allen Repos ausführen ... dann gibt's nichts zu commiten. Auf jeden Fall ist das so in meinem Umfeld. Das CI zieht sich alles aus dem git ....
* Installiere ich die neue Version mit "pip install -U --no-deps XYZ", bekommme ich mit einem "pip freeze" danach einen Stand meiner Umgebung, der sich u.U. gar nicht mehr mit "pip install -r requirements.txt" installieren lässt, weil die gepinnten Versionen nicht mehr zum Abhängigkeitsgraphen passen.
Mit pip-tools erhöhe ich einfach die Mindestversion der Abhängigkeit in der requirements.in Datei, lasse dann nochmal pip-compile laufen und habe danach eine valide requirements.txt Datei oder bekomme eben gleich einen Fehler und weiß, dass die Abhängigkeiten nicht zusammen passen (und nicht erst, wenn versucht wird, "pip install -r ..." im CI oder gar erst auf dem Staging/Produktionssystem auszuführen).
Ich hoffe, ich habe die Problematik damit etwas verdeutlichen können. Hier noch der Link zu einem interessanten Blog-Artikel über einen guten Workflow für pip-tools: ..
Ja, mir ist etwas klarer geworden wie du arbeitest. Gruß, Thomas -- http://www.thomas-guettler.de/
Noch ein Nachtrag zu dieser Diskussion: Am 24.03.2017 um 21:50 schrieb Thomas Güttler:
Ja, aber wenn du dann die Version einer Dependency aktualisieren willst, was machst du dann?
Das erhöhen der Version einer Dependency mache ich ja nicht aus Spaß an der Freude. Dafür gibt es Gründe. Ich passe das Modul an, dass die höhere Version braucht.
Wie ich das mache?
Ich erhöhe die >= Angabe von der install_requires-Zeile in setup.py
Unsere Applikation hat aber gar keine setup.py. Denn ist sie keine Library, die sich in einem anderen Projekt nutzen (importieren) lässt. Daher kann man auch kein Python-Paket dafür bauen (für den Build und Deployment gibt es ein spezielles Skript). Irgendwo müssen ja aber die Abhängigkeiten und deren Minimal- (und ggf. Maximal)-Versionen ja festgehalten werden. Deswegen nutzen wir dafür die requirements.in Dateien. Chris
Am 28.03.2017 um 15:58 schrieb Christopher Arndt:
Noch ein Nachtrag zu dieser Diskussion:
Am 24.03.2017 um 21:50 schrieb Thomas Güttler:
Ja, aber wenn du dann die Version einer Dependency aktualisieren willst, was machst du dann?
Das erhöhen der Version einer Dependency mache ich ja nicht aus Spaß an der Freude. Dafür gibt es Gründe. Ich passe das Modul an, dass die höhere Version braucht.
Wie ich das mache?
Ich erhöhe die >= Angabe von der install_requires-Zeile in setup.py
Unsere Applikation hat aber gar keine setup.py. Denn ist sie keine Library, die sich in einem anderen Projekt nutzen (importieren) lässt. Daher kann man auch kein Python-Paket dafür bauen (für den Build und Deployment gibt es ein spezielles Skript).
Ja, das ist der große Spaß an der Sache. Wenn es keine Python-Lib ist, was ist es dann? Ich habe dafür auch keinen klaren Begriff. Ich habe bloß festgestellt, dass ein Tool für Konfigurationsmanagement sinnvoll ist. Wir nehmen saltstack.
Irgendwo müssen ja aber die Abhängigkeiten und deren Minimal- (und ggf. Maximal)-Versionen ja festgehalten werden. Deswegen nutzen wir dafür die requirements.in Dateien.
Man könnte das auch in Salt machen.... Es gibt viele Wege die ans Ziel führen. Das Problem ist, dass in diesem Bereich kein "Best Pratice" Weg existiert. Bzw, ich keinen Weg kenne der von mehr als zwei-drei Leuten gegangen wird. In diesem Bereich bastelt jeder für sich ... schade. Gruß, Thomas -- Thomas Guettler http://www.thomas-guettler.de/
participants (2)
-
Christopher Arndt
-
Thomas Güttler