Gibt es eine Standardmethode, um Versionszeichenfolgen einem Python-Paket so zuzuordnen, dass ich Folgendes tun kann?
import foo
print foo.version
Ich würde mir vorstellen, dass es eine Möglichkeit gibt, diese Daten ohne zusätzliche Hardcodierung abzurufen, da bereits kleinere / größere Zeichenfolgen angegeben sind setup.py
. Alternative Lösung, die ich gefunden habe, war import __version__
in meinem zu haben foo/__init__.py
und dann von __version__.py
generiert zu haben setup.py
.
setup.py
. Siehe diese Frage .Antworten:
Keine direkte Antwort auf Ihre Frage, aber Sie sollten in Betracht ziehen, sie zu benennen
__version__
, nichtversion
.Dies ist fast ein Quasi-Standard. Viele Module in der Standardbibliothek werden verwendet
__version__
, und dies wird auch in Losen verwendet Modulen von Drittanbietern verwendet, sodass dies der Quasi-Standard ist.Normalerweise
__version__
ist es eine Zeichenfolge, aber manchmal ist es auch ein Float oder Tupel.Edit: Wie von S.Lott erwähnt (Danke!), Sagt PEP 8 es explizit:
Sie sollten auch sicherstellen, dass die Versionsnummer dem in PEP 440 beschriebenen Format entspricht ( PEP 386 eine frühere Version dieses Standards).
quelle
__version_info__
speziell? (Was Ihr eigenes doppeltes Unterstrichwort "erfindet".) [Als James kommentierte, taten Unterstriche nichts in Kommentaren, jetzt zeigen sie Betonung an, also schrieb James auch wirklich__version_info__
. --- ed.]Ich verwende eine einzelne
_version.py
Datei als "einmal kanonischen Ort", um Versionsinformationen zu speichern:Es bietet ein
__version__
Attribut.Es bietet die Standard-Metadatenversion. Daher wird es von
pkg_resources
oder anderen Tools erkannt , die die Paketmetadaten analysieren (EGG-INFO und / oder PKG-INFO, PEP 0345).Beim Erstellen Ihres Pakets wird Ihr Paket (oder etwas anderes) nicht importiert, was in einigen Situationen zu Problemen führen kann. (In den Kommentaren unten erfahren Sie, welche Probleme dies verursachen kann.)
Es gibt nur einen Ort, an dem die Versionsnummer notiert wird. Es gibt also nur einen Ort, an dem sie geändert werden kann, wenn sich die Versionsnummer ändert, und es besteht eine geringere Wahrscheinlichkeit für inkonsistente Versionen.
So funktioniert es: Der "einzige kanonische Ort" zum Speichern der Versionsnummer ist eine .py-Datei mit dem Namen "_version.py", die sich in Ihrem Python-Paket befindet, z. B. in
myniftyapp/_version.py
. Diese Datei ist ein Python-Modul, aber Ihre setup.py importiert sie nicht! (Das würde Feature 3 zunichte machen.) Stattdessen weiß Ihre setup.py, dass der Inhalt dieser Datei sehr einfach ist, etwa:Und so öffnet Ihre setup.py die Datei und analysiert sie mit Code wie:
Dann übergibt Ihre setup.py diese Zeichenfolge als Wert des Arguments "version" an
setup()
und erfüllt damit Merkmal 2.Um Funktion 1 zu erfüllen, können Sie Ihr Paket (zur Laufzeit, nicht zur Setup-Zeit!) Die _Versionsdatei
myniftyapp/__init__.py
wie folgt importieren lassen :Hier ist ein Beispiel für diese Technik , die ich seit Jahren verwende.
Der Code in diesem Beispiel ist etwas komplizierter, aber das vereinfachte Beispiel, das ich in diesen Kommentar geschrieben habe, sollte eine vollständige Implementierung sein.
Hier ist ein Beispielcode zum Importieren der Version .
Wenn Sie etwas falsch mit diesem Ansatz sehen, lassen Sie es mich bitte wissen.
quelle
setup.py
. Wenn es versucht, zuerst die volle Tiefe zu machen und alle Deps zu machen, bevor es dieses macht, würde es stecken bleiben, wenn es kreisförmige Deps gäbe. Wenn es jedoch versucht, dieses Paket vor der Installation der Abhängigkeiten zu erstellensetup.py
, kann es beim Importieren Ihres Pakets nicht unbedingt seine Deps oder die richtigen Versionen seiner Deps importieren.execfile("myniftyapp/_version.py")
in setup.py zu arbeiten, anstatt zu versuchen, den Versionscode manuell zu analysieren. Vorgeschlagen in stackoverflow.com/a/2073599/647002 - eine Diskussion dort kann ebenfalls hilfreich sein.Umgeschrieben 2017-05
Nachdem ich mehr als zehn Jahre Python-Code geschrieben und verschiedene Pakete verwaltet hatte, kam ich zu dem Schluss, dass DIY möglicherweise nicht der beste Ansatz ist.
Ich habe angefangen,
pbr
package für die Versionsverwaltung in meinen Paketen zu verwenden. Wenn Sie git als SCM verwenden, passt dies wie von Zauberhand in Ihren Workflow und spart Ihnen wochenlange Arbeit (Sie werden überrascht sein, wie komplex das Problem sein kann).Bis heute ist pbr die Nummer 11 der am häufigsten verwendeten Python-Pakete, und das Erreichen dieses Levels beinhaltete keine schmutzigen Tricks: war nur eine: Beheben eines häufigen Verpackungsproblems auf sehr einfache Weise.
pbr
kann mehr von der Paketwartungslast übernehmen, ist nicht auf die Versionierung beschränkt, zwingt Sie jedoch nicht dazu, alle Vorteile zu nutzen.Um Ihnen eine Vorstellung davon zu geben, wie es aussieht, pbr in einem Commit zu übernehmen, werfen Sie einen Blick auf pbr
Wahrscheinlich haben Sie festgestellt, dass die Version überhaupt nicht im Repository gespeichert ist. PBR erkennt es an Git-Zweigen und -Tags.
Sie müssen sich keine Gedanken darüber machen, was passiert, wenn Sie kein Git-Repository haben, da pbr die Version beim Packen oder Installieren der Anwendungen "kompiliert" und zwischenspeichert, sodass keine Laufzeitabhängigkeit von Git besteht.
Alte Lösung
Hier ist die beste Lösung, die ich bisher gesehen habe, und sie erklärt auch, warum:
Innen
yourpackage/version.py
:Innen
yourpackage/__init__.py
:Innen
setup.py
:Wenn Sie einen anderen Ansatz kennen, der besser zu sein scheint, lassen Sie es mich wissen.
quelle
from .version import __version__
in setup.py?setup.py
es ausgeführt wird - versuchen Sie es, Sie erhalten eine Fehlermeldung (oder zumindest habe ich :-))Gemäß dem zurückgestellten PEP 396 (Modulversionsnummern) wird ein Weg vorgeschlagen, dies zu tun. Es beschreibt mit Begründung einen (zugegebenermaßen optionalen) Standard für Module, die folgen sollen. Hier ist ein Ausschnitt:
quelle
Obwohl dies wahrscheinlich viel zu spät ist, gibt es eine etwas einfachere Alternative zur vorherigen Antwort:
(Und es wäre ziemlich einfach, automatisch inkrementierende Teile von Versionsnummern mit in eine Zeichenfolge zu konvertieren
str()
.)Nach allem, was ich gesehen habe, neigen die Leute dazu, bei der Verwendung so etwas wie die zuvor erwähnte Version zu verwenden
__version_info__
und es als solches als Tupel von Ints zu speichern. Ich verstehe dies jedoch nicht ganz, da ich bezweifle, dass es Situationen gibt, in denen Sie mathematische Operationen wie Addition und Subtraktion von Teilen von Versionsnummern für einen anderen Zweck als Neugier oder automatische Inkrementierung ausführen würden (und selbst dann)int()
undstr()
kann ziemlich einfach verwendet werden). (Andererseits besteht die Möglichkeit, dass der Code eines anderen ein numerisches Tupel anstelle eines Zeichenfolgentupels erwartet und somit fehlschlägt.)Dies ist natürlich meine eigene Ansicht, und ich würde gerne die Beiträge anderer zur Verwendung eines numerischen Tupels begrüßen.
Wie Shezi mich erinnerte, haben (lexikalische) Vergleiche von Zahlenfolgen nicht unbedingt das gleiche Ergebnis wie direkte numerische Vergleiche. Dazu wären führende Nullen erforderlich. Am Ende
__version_info__
würde das Speichern (oder wie auch immer es genannt werden würde) als Tupel ganzzahliger Werte effizientere Versionsvergleiche ermöglichen.quelle
__version_info__ = (1,2,3)
__version_info__ = (0, 1, 0) __version__ = '.'.join(map(str, __version_info__))
__version__ = '.'.join(__version_info__)
ist, dass__version_info__ = ('1', '2', 'beta')
wird1.2.beta
, nicht1.2beta
oder1.2 beta
Viele dieser Lösungen hier ignorieren
git
Versions-Tags, was bedeutet, dass Sie die Version an mehreren Stellen verfolgen müssen (schlecht). Ich ging dies mit folgenden Zielen an:git
Repo abgit tag
/push
undsetup.py upload
Schritte mit einem einzigen Befehl, der keine Eingaben akzeptiert.Wie es funktioniert:
Aus einem
make release
Befehl heraus wird die zuletzt getaggte Version im Git-Repo gefunden und erhöht. Das Tag wird zurückgeschobenorigin
.Das
Makefile
speichert die Version dort,src/_version.py
wo sie gelesen wirdsetup.py
und auch in der Version enthalten ist. Nicht_version.py
in die Quellcodeverwaltung einchecken !setup.py
Befehl liest die neue Versionszeichenfolge auspackage.__version__
.Einzelheiten:
Makefile
Das
release
Ziel erhöht immer die Ziffer der 3. Version, aber Sie können dasnext_minor_ver
oder verwenden,next_major_ver
um die anderen Ziffern zu erhöhen. Die Befehle basieren auf demversionbump.py
Skript, das im Stammverzeichnis des Repos eingecheckt istversionbump.py
Dies macht das schwere Heben, wie die Versionsnummer von verarbeitet und erhöht wird
git
.__init__.py
Die
my_module/_version.py
Datei wird in importiertmy_module/__init__.py
. Fügen Sie hier eine statische Installationskonfiguration ein, die Sie mit Ihrem Modul verteilen möchten.setup.py
Der letzte Schritt besteht darin, die Versionsinformationen aus dem
my_module
Modul zu lesen .Damit dies alles funktioniert, muss Ihr Repo mindestens ein Versions-Tag enthalten, um zu starten.
quelle
versionbump.py
wenn wir ein fantastisches Bumpversion- Paket für Python haben._version.py
mit Versionskontrolle verfolgt werden?Ich verwende eine JSON-Datei im Paketverzeichnis. Dies entspricht den Anforderungen von Zooko.
Innen
pkg_dir/pkg_info.json
:Innen
setup.py
:Innen
pkg_dir/__init__.py
:Ich habe auch andere Informationen
pkg_info.json
wie den Autor eingegeben. Ich verwende gerne JSON, weil ich die Verwaltung von Metadaten automatisieren kann.quelle
Erwähnenswert ist auch, dass dies
__version__
nicht nur ein Semi-Standard ist. In Python ist__version_info__
das also ein Tupel. In den einfachen Fällen können Sie einfach so etwas tun:... und Sie können die
__version__
Zeichenfolge aus einer Datei oder was auch immer erhalten.quelle
__version_info__
?__version_info__ = (1, 2, 3)
und__version__ = '.'.join(map(str, __version_info__))
) durchzuführen.__version__ = '.'.join(str(i) for i in __version_info__)
- etwas länger, aber pythonischer.i
keine Bedeutung hat,version_num
etwas lang und mehrdeutig ist…). Ich nehme sogar die Existenz vonmap()
in Python als starken Hinweis darauf, dass es hier verwendet werden sollte, da wir hier den typischen Anwendungsfall vonmap()
(Verwendung mit einer vorhandenen Funktion) tun müssen - ich sehe nicht viele andere vernünftige Verwendungen.Es scheint keine Standardmethode zum Einbetten einer Versionszeichenfolge in ein Python-Paket zu geben. Die meisten Pakete, die ich gesehen habe, verwenden eine Variante Ihrer Lösung, z. B. eitner
Betten Sie die Version ein
setup.py
undsetup.py
generieren Sie ein Modul (z. B.version.py
), das nur Versionsinformationen enthält, die von Ihrem Paket importiert wurden, oderDas Gegenteil: Fügen Sie die Versionsinformationen in Ihr Paket selbst ein und importieren Sie diese , um die Version festzulegen
setup.py
quelle
Pfeil behandelt es auf interessante Weise.
Jetzt (seit 2e5031b )
In
arrow/__init__.py
:In
setup.py
:Vor
In
arrow/__init__.py
:In
setup.py
:quelle
file_text
?pip install -e .
wenn es in einem Entwicklungszweig ausgeführt wird oder etwas beim Testen. setup.py sollte sich unbedingt nicht auf den Import des Pakets verlassen, das gerade installiert wird, um die Parameter für die Bereitstellung zu ermitteln. Huch.Ich habe auch einen anderen Stil gesehen:
quelle
.VERSION
bedeutet nicht, dass Sie nicht implementieren müssen__version__
.django
im Projekt?Verwenden von
setuptools
undpbr
Es gibt keine Standardmethode zum Verwalten der Version, aber die Standardmethode zum Verwalten Ihrer Pakete ist
setuptools
.Die beste Lösung, die ich insgesamt für die Verwaltung der Version gefunden habe, ist die Verwendung
setuptools
mit dempbr
Erweiterung. Dies ist jetzt meine Standardmethode zum Verwalten der Version.Das Einrichten Ihres Projekts für die vollständige Verpackung kann für einfache Projekte übertrieben sein. Wenn Sie jedoch die Version verwalten müssen, sind Sie wahrscheinlich auf der richtigen Ebene, um einfach alles einzurichten. Dadurch wird Ihr Paket auch bei PyPi freigegeben kann sodass jeder es herunterladen und mit Pip verwenden kann.
PBR verschiebt die meisten Metadaten aus den
setup.py
Tools in einesetup.cfg
Datei, die dann als Quelle für die meisten Metadaten verwendet wird, einschließlich der Version. Auf diese Weise können die Metadaten bei Bedarf in eine ausführbare Datei gepacktpyinstaller
werden (falls ja, benötigen Sie wahrscheinlich diese Informationen ), und die Metadaten werden von den anderen Paketverwaltungs- / Setup-Skripten getrennt. Sie können die Versionszeichenfolge direktsetup.cfg
manuell aktualisieren , und sie wird in die Datei gezogen*.egg-info
Erstellen Ihrer Paketversionen Ordner . Ihre Skripte können dann mit verschiedenen Methoden aus den Metadaten auf die Version zugreifen (diese Prozesse werden in den folgenden Abschnitten beschrieben).Wenn Sie Git für VCS / SCM verwenden, ist dieses Setup sogar noch besser, da viele Metadaten von Git abgerufen werden, sodass Ihr Repo Ihre primäre Wahrheitsquelle für einige der Metadaten sein kann, einschließlich Version, Autoren, Änderungsprotokolle, usw. Für die spezifische Version wird eine Versionszeichenfolge für das aktuelle Commit basierend auf den Git-Tags im Repo erstellt.
setup.py
und einersetup.cfg
Datei mit den Metadaten.Da PBR Version, Autor, Änderungsprotokoll und andere Informationen direkt aus Ihrem Git-Repo abruft, sind einige der Metadaten in
setup.cfg
und automatisch generiert werden, wenn eine Distribution für Ihr Paket erstellt wird (mithilfe vonsetup.py
).Aktuelle Echtzeitversion
setuptools
wird die neuesten Informationen in Echtzeit mit abrufensetup.py
:Dadurch wird die neueste Version entweder aus dem
setup.cfg
Datei oder aus dem Git-Repo abgerufen, basierend auf dem zuletzt vorgenommenen Commit und den im Repo vorhandenen Tags. Dieser Befehl aktualisiert die Version in einer Distribution jedoch nicht.Aktualisierung der Version
Wenn Sie eine Distribution mit
setup.py
(py setup.py sdist
z. B.) erstellen , werden alle aktuellen Informationen extrahiert und in der Distribution gespeichert. Dies führt im Wesentlichen densetup.py --version
Befehl aus und speichert diese Versionsinformationen in dempackage.egg-info
Ordner in einer Reihe von Dateien, in denen Verteilungsmetadaten gespeichert sind.Zugriff auf die Version über ein Skript
Sie können auf die Metadaten aus dem aktuellen Build in Python-Skripten im Paket selbst zugreifen. Für die Version gibt es zum Beispiel verschiedene Möglichkeiten, dies zu tun, die ich bisher gefunden habe:
Sie können eine davon direkt in Ihr
__init__.py
Paket einfügen, um die Versionsinformationen wie folgt zu extrahieren, ähnlich wie bei einigen anderen Antworten:quelle
Nach mehreren Stunden des Versuchs, die einfachste zuverlässige Lösung zu finden, sind hier die Teile:
Erstellen Sie eine version.py-Datei im Ordner Ihres Pakets "/ mypackage":
in setup.py:
im Hauptordner init .py:
Die
exec()
Funktion führt das Skript außerhalb von Importen aus, da setup.py ausgeführt wird, bevor das Modul importiert werden kann. Sie müssen die Versionsnummer immer noch nur in einer Datei an einem Ort verwalten, aber leider befindet sie sich nicht in setup.py. (Das ist der Nachteil, aber keine Importfehler zu haben, ist der Vorteil)quelle
Seit diese Frage zum ersten Mal gestellt wurde, wurden viele Arbeiten zur einheitlichen Versionierung und zur Unterstützung von Konventionen abgeschlossen . Schmackhafte Optionen werden nun detailliert in der Python Verpackung Benutzerhandbuch . Bemerkenswert ist auch, dass die Versionsnummernschemata in Python gemäß PEP 440 relativ streng sind. Daher ist es wichtig , dass die Dinge gesund bleiben, wenn Ihr Paket im Cheese Shop veröffentlicht wird .
Hier ist eine verkürzte Aufschlüsselung der Versionsoptionen:
setup.py
( setuptools ) und erhalten Sie die Version.__init__.py
die Quellcodeverwaltung als auch die Quellcodeverwaltung zu aktualisieren ), z. B. Stoß2version , Änderungen oder zest.releaser .__version__
in einem bestimmten Modul auf eine globale Variable.setup.py
Release fest und verwenden Sie importlib.metadata , um ihn zur Laufzeit abzurufen . (Achtung, es gibt Versionen vor 3.8 und nach 3.8.)__version__
insample/__init__.py
und importieren Sie das Beispiel insetup.py
.HINWEIS : (7) ist möglicherweise der modernste Ansatz (Build-Metadaten sind unabhängig von Code, der durch Automatisierung veröffentlicht wird). Auch HINWEIS dass , wenn Setup für Paket Freigabe verwendet wird , dass ein einfacher
python3 setup.py --version
die Version direkt berichten.quelle
Wenn Sie NumPy distutils verwenden,
numpy.distutils.misc_util.Configuration
gibt es einemake_svn_version_py()
Methode, mit der die Revisionsnummerpackage.__svn_version__
in die Variable eingebettet wirdversion
.quelle
version.py
Datei nur mit__version__ = <VERSION>
param in der Datei. In dersetup.py
Datei , um den Import__version__
param und seinen Wert in der Put -setup.py
Datei wie folgt:version=__version__
setup.py
Datei mit zu verwendenversion=<CURRENT_VERSION>
- die CURRENT_VERSION ist fest codiert.Da wir die Version in der Datei nicht jedes Mal manuell ändern möchten, wenn wir ein neues Tag erstellen (bereit, eine neue Paketversion freizugeben), können wir Folgendes verwenden:
Ich kann das Bumpversion- Paket nur empfehlen . Ich benutze es seit Jahren, um eine Version zu stoßen.
Beginnen Sie mit dem Hinzufügen
version=<VERSION>
zu Ihrersetup.py
Datei, falls Sie diese noch nicht haben.Sie sollten jedes Mal, wenn Sie eine Version stoßen, ein kurzes Skript wie dieses verwenden:
Dann fügen Sie eine Datei pro Repo genannt:
.bumpversion.cfg
:Hinweis:
__version__
Parameter unterversion.py
Datei verwenden, wie es in anderen Beiträgen vorgeschlagen wurde, und die Bumpversion-Datei wie folgt aktualisieren:[bumpversion:file:<RELATIVE_PATH_TO_VERSION_FILE>]
git commit
odergit reset
alles in Ihrem Repo, sonst erhalten Sie einen schmutzigen Repo-Fehler.quelle
bumpversion
, ohne es wird es nicht funktionieren. Verwenden Sie die neueste Version.version.py
oder mit zu verfolgenbumpversion
?__version__
version.py zu aktualisieren und den Parameterwert in die Datei setup.py zu übernehmen. Meine Lösung wird in der Produktion verwendet und ist eine gängige Praxis. Hinweis: Um ganz klar zu sein, ist die Verwendung von Bumpversion als Teil eines Skripts die beste Lösung. Fügen Sie sie in Ihr CI ein und es wird automatisch ausgeführt.Wenn Sie CVS (oder RCS) verwenden und eine schnelle Lösung wünschen, können Sie Folgendes verwenden:
(Natürlich wird die Revisionsnummer durch CVS ersetzt.)
Auf diese Weise erhalten Sie eine druckfreundliche Version und Versionsinformationen, mit denen Sie überprüfen können, ob das zu importierende Modul mindestens die erwartete Version aufweist:
quelle
__version__
? Wie würde man die Versionsnummer mit dieser Lösung erhöhen?