Wie kann ich die in setup.py
meinem Paket definierte Version (für --version
oder für andere Zwecke) erhalten?
python
setuptools
Elmarco
quelle
quelle
Antworten:
Versionszeichenfolge der bereits installierten Distribution abfragen
Um die Version zur Laufzeit aus Ihrem Paket abzurufen (was Ihre Frage tatsächlich zu stellen scheint), können Sie Folgendes verwenden:
Speichern Sie die Versionszeichenfolge zur Verwendung während der Installation
Wenn Sie in die andere Richtung gehen möchten (was andere Antwortautoren hier anscheinend gedacht haben), fügen Sie die Versionszeichenfolge in eine separate Datei ein und lesen Sie den Inhalt dieser Datei ein
setup.py
.Sie können eine version.py in Ihrem Paket mit einer
__version__
Zeile erstellen und diese dann aus setup.py mit lesenexecfile('mypackage/version.py')
, sodass sie__version__
im Namespace setup.py festgelegt wird.Wenn Sie eine viel einfachere Methode wünschen, die mit allen Python-Versionen und sogar Nicht-Python-Sprachen funktioniert, die möglicherweise Zugriff auf die Versionszeichenfolge benötigen:
Speichern Sie die Versionszeichenfolge als einzigen Inhalt einer
VERSION
Nur- Text-Datei mit dem Namen z. B. und lesen Sie diese Datei währendsetup.py
.Dieselbe
VERSION
Datei funktioniert dann genauso gut in jedem anderen Programm, auch in Nicht-Python-Programmen, und Sie müssen die Versionszeichenfolge für alle Programme nur an einer Stelle ändern.Warnung vor Rennbedingungen während der Installation
Übrigens, importieren Sie Ihr Paket NICHT aus Ihrer setup.py, wie in einer anderen Antwort hier vorgeschlagen: Es scheint für Sie zu funktionieren (da Sie bereits die Abhängigkeiten Ihres Pakets installiert haben), aber es wird neuen Benutzern Ihres Pakets Schaden zufügen , da sie Ihr Paket nicht installieren können, ohne zuerst die Abhängigkeiten manuell zu installieren.
quelle
execfile
funktioniert wirklich gut ... aber (leider) funktioniert nicht mit Python 3.with open('mypackage/version.py') as f: exec(f.read())
anstelle von verwendenexecfile('mypackage/version.py')
. (Von stackoverflow.com/a/437857/647002 )Beispielstudie:
mymodule
Stellen Sie sich diese Konfiguration vor:
Stellen Sie sich dann ein übliches Szenario vor, in dem Sie Abhängigkeiten haben und
setup.py
wie folgt aussehen:Und ein Beispiel
__init__.py
:Und zum Beispiel
myclasses.py
:Problem Nr. 1: Importieren
mymodule
während des SetupsWenn Sie dann während des Setups
setup.py
importieren, erhalten Sie höchstwahrscheinlich eine . Dies ist ein sehr häufiger Fehler, wenn Ihr Paket Abhängigkeiten aufweist. Wenn Ihr Paket keine anderen Abhängigkeiten als die integrierten enthält, sind Sie möglicherweise sicher. Dies ist jedoch keine gute Praxis. Der Grund dafür ist, dass es nicht zukunftssicher ist; Sagen Sie morgen, Ihr Code muss eine andere Abhängigkeit verbrauchen.mymodule
ImportError
Problem Nr. 2: Wo ist mein
__version__
?Wenn Sie codieren
__version__
insetup.py
dann kann es nicht mit der Version übereinstimmen , dass Sie in Ihrem Modul versenden würden. Um konsistent zu sein, würden Sie es an einer Stelle ablegen und an derselben Stelle lesen, wenn Sie es benötigen. Bei Verwendungimport
kann das Problem Nr. 1 auftreten.Lösung: à la
setuptools
Sie würden eine Kombination aus verwenden
open
,exec
und ein dict für bietenexec
hinzuzufügen Variablen:Und in
mymodule/version.py
der Version aussetzen:Auf diese Weise wird die Version mit dem Modul geliefert, und Sie haben keine Probleme beim Einrichten eines Moduls mit fehlenden Abhängigkeiten (das noch installiert werden muss).
quelle
Die beste Technik besteht darin,
__version__
in Ihrem Produktcode zu definieren und ihn dann von dort in setup.py zu importieren. Dies gibt Ihnen einen Wert, den Sie in Ihrem laufenden Modul lesen können und der nur an einer Stelle definiert werden kann.Die Werte in setup.py werden nicht installiert, und setup.py bleibt nach der Installation nicht erhalten.
Was ich (zum Beispiel) in Coverage.py gemacht habe:
UPDATE (2017): Coverage.py importiert sich nicht mehr selbst, um die Version zu erhalten. Durch das Importieren Ihres eigenen Codes kann es deinstalliert werden, da Ihr Produktcode versucht, Abhängigkeiten zu importieren, die noch nicht installiert sind, da sie durch setup.py installiert werden.
quelle
__version__
auf irgendeine Weise beschädigt ist, wird auch Ihr Import unterbrochen. Python kann nicht nur die gewünschten Anweisungen interpretieren. @pjeby ist richtig: Wenn Ihr Modul andere Module importieren muss, sind diese möglicherweise noch nicht installiert und es wird chaotisch. Diese Technik funktioniert, wenn Sie darauf achten, dass der Import keine lange Kette anderer Importe verursacht.pip install <packagename>
die folgende Fehlermeldung erhalte :ImportError: No module named <packagename>
. Bitte warnen Sie Ihre Leser, dass Sie solche setup.py-Dateien in Umgebungen, in denen das Paket noch nicht installiert ist, nicht ausführen können!Ihre Frage ist etwas vage, aber ich denke, Sie fragen, wie Sie sie spezifizieren sollen.
Sie müssen wie folgt definieren
__version__
:Und dann können Sie bestätigen, dass setup.py die gerade angegebene Version kennt:
quelle
Ich war mit diesen Antworten nicht zufrieden ... wollte weder Setuptools benötigen noch ein ganzes separates Modul für eine einzelne Variable erstellen, also habe ich mir diese ausgedacht.
Wenn Sie sicher sind, dass das Hauptmodul im pep8-Stil vorliegt und dies auch bleibt:
Wenn Sie besonders vorsichtig sein und einen echten Parser verwenden möchten:
setup.py ist so etwas wie ein Wegwerfmodul, also kein Problem, wenn es etwas hässlich ist.
Update: Lustigerweise habe ich mich in den letzten Jahren davon entfernt und angefangen, eine separate Datei im Paket namens zu verwenden
meta.py
. Ich habe dort viele Metadaten eingefügt, die ich möglicherweise häufig ändern möchte. Also nicht nur für einen Wert.quelle
ast.get_docstring()
mit einigen.split('\n')[0].strip()
usw. verwenden, um automatischdescription
aus der Quelle auszufüllen . Eine Sache weniger, um synchron zu bleibenErstellen Sie eine Datei in Ihrem Quellbaum, z. B. in yourbasedir / yourpackage / _version.py. Lassen Sie diese Datei nur eine einzige Codezeile enthalten, wie folgt:
__version__ = "1.1.0-r4704"
Öffnen Sie dann in Ihrer setup.py diese Datei und analysieren Sie die Versionsnummer wie folgt:
Schließlich in
yourbasedir/yourpackage/__init__.py
import _version wie folgt:Ein Beispiel für Code, der dies tut, ist das von mir verwaltete "pyutil" -Paket. (Siehe PyPI oder Google-Suche - Stackoverflow verbietet mir, einen Hyperlink in diese Antwort aufzunehmen.)
@pjeby ist richtig, dass Sie Ihr Paket nicht aus seiner eigenen setup.py importieren sollten. Das funktioniert, wenn Sie es testen, indem Sie einen neuen Python-Interpreter erstellen und als erstes setup.py ausführen:
python setup.py
aber es gibt Fälle, in denen es nicht funktioniert. Das liegt daran,import youpackage
dass Sie nicht das aktuelle Arbeitsverzeichnis für ein Verzeichnis mit dem Namen "yourpackage" lesen müssen, sondern im aktuellensys.modules
nach einem Schlüssel "yourpackage" suchen und dann verschiedene Dinge tun müssen, wenn es nicht vorhanden ist. Es funktioniert also immer, wenn Sie es tun,python setup.py
weil Sie ein frisches, leeres habensys.modules
, aber das funktioniert im Allgemeinen nicht.Was ist zum Beispiel, wenn py2exe Ihre setup.py im Rahmen des Packens einer Anwendung ausführt? Ich habe einen Fall wie diesen gesehen, in dem py2exe die falsche Versionsnummer auf ein Paket gesetzt hat, weil das Paket seine Versionsnummer von erhalten hat
import myownthing
in seiner setup.py, aber eine andere Version dieses Pakets wurde zuvor während des py2exe-Laufs importiert. Was ist, wenn setuptools, easy_install, Distribute oder distutils2 versuchen, Ihr Paket als Teil eines Installationsprozesses für ein anderes Paket zu erstellen, das von Ihrem abhängt? Dann, ob Ihr Paket zum Zeitpunkt der Auswertung von setup.py importierbar ist oder ob bereits eine Version Ihres Pakets vorhanden ist, die während des Lebens dieses Python-Interpreters importiert wurde, oder ob für den Import Ihres Pakets zuerst andere Pakete installiert werden müssen oder hat Nebenwirkungen, kann die Ergebnisse ändern. Ich hatte mehrere Probleme mit dem Versuch, Python-Pakete wiederzuverwenden, was Probleme für Tools wie py2exe und setuptools verursachte, da deren setup.py das Paket selbst importiert, um seine Versionsnummer zu finden.Übrigens spielt diese Technik gut mit Tools, mit denen die
yourpackage/_version.py
Datei automatisch für Sie erstellt werden kann, z. B. indem Sie Ihren Revisionskontrollverlauf lesen und eine Versionsnummer schreiben, die auf dem neuesten Tag im Revisionskontrollverlauf basiert. Hier ist ein Tool, das das für darcs macht: http://tahoe-lafs.org/trac/darcsver/browser/trunk/README.rst und hier ist ein Code-Snippet, das dasselbe für git macht: http: // github .com / warner / python-ecdsa / blob / 0ed702a9d4057ecf33eea969b8cf280eaccd89a1 / setup.py # L34quelle
Dies sollte auch funktionieren, indem reguläre Ausdrücke verwendet werden und abhängig von den Metadatenfeldern ein Format wie das folgende verwendet wird:
Verwenden Sie zu Beginn Ihrer setup.py Folgendes:
Danach können Sie die Metadaten in Ihrem Skript folgendermaßen verwenden:
quelle
Mit einer Struktur wie dieser:
wo version.py enthält:
Sie können dies in setup.py tun :
Dies verursacht keine Probleme mit den Abhängigkeiten, die Sie in Ihrem mymodule / __ init__.py haben
quelle
Um zu vermeiden, dass eine Datei importiert wird (und somit ihr Code ausgeführt wird), können Sie sie analysieren und das
version
Attribut aus dem Syntaxbaum wiederherstellen :Dieser Code versucht, die
__version__
oderVERSION
-Zuweisung auf der obersten Ebene der Modulrückgabe als Zeichenfolgenwert zu finden. Die rechte Seite kann entweder eine Zeichenfolge oder ein Tupel sein.quelle
Es gibt tausend Möglichkeiten, eine Katze zu häuten - hier ist meine:
quelle
Bereinigen von https://stackoverflow.com/a/12413800 von @ gringo-suave:
quelle
Das ist eklig und muss verfeinert werden (es kann sogar einen ungedeckten Mitgliederaufruf in pkg_resources geben, den ich verpasst habe), aber ich verstehe einfach nicht, warum dies nicht funktioniert oder warum es bisher niemand vorgeschlagen hat (Googeln hat es getan) nicht aufgedreht) ... beachte, dass dies Python 2.x ist und pkg_resources erfordern würde (seufz):
quelle
Wir wollten die Meta - Informationen über unser Paket setzen
pypackagery
in__init__.py
, konnte aber nicht , da sie von Drittanbietern Abhängigkeiten wie PJ Eby hat bereits (siehe seine Antwort und die Warnung in Bezug auf die Race - Bedingung) hingewiesen.Wir haben es gelöst, indem wir ein separates Modul erstellt haben
pypackagery_meta.py
, das nur die Metainformationen enthält:importierte dann die Metainformationen in
packagery/__init__.py
:und schließlich verwendet in
setup.py
:Sie müssen das Setup-Argument
pypackagery_meta
in Ihr Paket aufnehmenpy_modules
. Andernfalls können Sie es bei der Installation nicht importieren, da es der gepackten Distribution fehlen würde.quelle
Erstellen Sie einfach und direkt eine Datei
source/package_name/version.py
mit dem folgenden Inhalt:Anschließend
source/package_name/__init__.py
importieren Sie in Ihre Datei die Version, die andere Benutzer verwenden können:Jetzt können Sie dies anziehen
setup.py
Getestet dies mit Python
2.7
,3.3
,3.4
,3.5
,3.6
und3.7
auf Linux, Windows und Mac OS. Ich habe mein Paket verwendet, das Integrations- und Unit-Tests für alle diese Plattformen enthält. Sie können die Ergebnisse von.travis.yml
undappveyor.yml
hier sehen:Eine alternative Version verwendet den Kontextmanager:
Sie können das
codecs
Modul auch verwenden, um Unicode-Fehler sowohl in Python2.7
als auch in Python zu behandeln3.6
Wenn Sie ein Python-Modul zu 100% in C / C ++ mit Python C-Erweiterungen schreiben, können Sie dasselbe tun, jedoch C / C ++ anstelle von Python verwenden.
Erstellen Sie in diesem Fall Folgendes
setup.py
:Welches liest die Version aus der Datei
version.h
:Vergessen Sie jedoch nicht, das zu erstellen
MANIFEST.in
, um dieversion.h
Datei einzuschließen:Und es ist in die Hauptanwendung integriert mit:
Verweise:
quelle
Bereitstellen der Konvention zur Paket- und Dateinamenkonvention für Indexpakete:
Beispiel für die Konvertierung der dynamischen Pip-Version:
Sieg:
Mac:
Suchen Sie das Beispiel setup.py ruft die dynamische Pip-Version auf, die mit git commit übereinstimmt
quelle
Ich verwende eine Umgebungsvariable wie unten
VERSION = 0.0.0 python setup.py sdist bdist_wheel
In setup.py
Zur Konsistenzprüfung mit der Packer-Version verwende ich das folgende Skript.
quelle