De manière Standard pour intégrer la version en python package?
Est-il un moyen standard pour associer chaîne de version avec un paquet python dans une telle manière que je pourrais faire la suite?
import foo
print foo.version
J'imagine, il y a une certaine façon de récupérer des données sans aucun supplément de coder en dur, depuis le mineur/majeur cordes sont spécifiés dans setup.py
déjà. Autre solution que j'ai trouvé était d'avoir import __version__
dans mon foo/__init__.py
puis ont __version__.py
généré par setup.py
.
- Pour info, il y a une très bonne vue d'ensemble sur: packaging.python.org/en/latest/...
- La Version d'un paquet peut être récupéré à partir de métadonnées avec setuptools, de sorte que dans de nombreux cas, de mettre uniquement sur la version en
setup.py
est assez. Voir cette question. - Pour info, il existe 5 modèles communs afin de maintenir la source unique de la vérité (au niveau de la configuration et de temps d'exécution) pour le numéro de version.
- Python la documentation de listes 7 options différentes pour un seul acidification. N'est-ce pas en contradiction avec la notion de "source unique de vérité"?
- pas sûr de ce que vous demandez. Il existe de nombreuses façons qui y sont énumérés, parce que l'emballage guide ne veut pas être opiniâtre.
Vous devez vous connecter pour publier un commentaire.
Pas directement la réponse à votre question, mais vous devriez envisager de nommer
__version__
, pasversion
.C'est presque un quasi-standard. De nombreux modules de la bibliothèque standard, utilisation
__version__
, et c'est aussi utilisé dans beaucoup de la 3e partie des modules, c'est donc la quasi-standard.Généralement,
__version__
est une chaîne, mais parfois, c'est aussi un float ou un tuple.Edit: comme mentionné par S. Lott (Merci!), PEP 8 il est dit explicitement:
Vous devez également vous assurer que le numéro de version est conforme au format décrit dans PEP 440 (PEP 386 une version précédente de la présente norme).
__version_info__
en particulier? (Qui "invente" votre propre double-trait de soulignement de mots.) [Quand James a commenté, des traits de soulignement n'a rien fait dans les commentaires, maintenant, ils indiquent l'accent, de sorte que James a vraiment écrit__version_info__
trop. ---ed.]__version__
à suivre les règles de PEP 386, qui permettent à des numéros de version pour être fiable comparé.- Je utiliser un seul
_version.py
fichier en tant que "une fois que cannonical place" pour stocker les informations de version:Il fournit un
__version__
attribut.Il fournit la norme de métadonnées version. Par conséquent, il sera détecté par
pkg_resources
ou d'autres outils qui analysent le paquet de métadonnées (EGG-INFO et/ou PKG-INFO, PEP 0345).Il n'a pas d'importation de votre colis (ou autre chose) lors de la construction de votre colis, ce qui peut causer des problèmes dans certaines situations. (Voir les commentaires ci-dessous sur ce que les problèmes que cela peut causer.)
Il n'y a qu'un seul endroit que le numéro de version est écrite, donc il n'y a qu'un seul endroit à en changer lorsque le numéro de version change, et il ya moins de chance de versions incompatibles.
Voici comment ça fonctionne: le "canonique" pour enregistrer le numéro de version est un .py fichier, nommé "_version.py" ce qui est dans votre paquet Python, par exemple dans
myniftyapp/_version.py
. Ce fichier est un module Python, mais votre setup.py ne pas l'importer! (Qui irait à l'encontre de fonction 3.) Au lieu de votre setup.py sait que le contenu de ce fichier est très simple, quelque chose comme:Et donc votre setup.py ouvre le fichier et l'analyse, avec un code comme:
Alors votre setup.py passe d'une chaîne de caractères comme la valeur de la "version" argument de
setup()
, satisfaisant ainsi de caractéristique 2.Pour satisfaire caractéristique 1, vous pouvez avoir votre colis (au moment de l'exécution, et non pas au moment de l'installation!) importer le _version fichier de
myniftyapp/__init__.py
comme ceci:Ici est un exemple de cette technique que j'ai utilisé pendant des années.
Le code de cet exemple est un peu plus compliqué, mais l'exemple simplifié que j'ai écrit dans ce commentaire doit être une mise en œuvre complète.
Ici est exemple de code de l'importation de la version.
Si vous voyez quelque chose de mal avec cette approche, s'il vous plaît laissez-moi savoir.
setup.py
est en cours d'exécution dans un fraîchement créé Python processus et de votre répertoire de travail courant est le répertoire qui contient votre projet, puis il va travailler. C'est la façon la plus commune que les programmeurs exécutersetup.py
, ils pensent donc que c'est le seul moyen. Mais il existe d'autres moyens! Des outils comme py2exe exécuter une seule Python processus, puis de charger et d'exécuter lesetup.py
des scripts à partir d'un projet après l'autre (alors que l'emballage de tous ensemble). Supposons que certains de code Python qui a couru avant votresetup.py
script importé d'une autre version de votre module.setuptools
oupip
doit faire deux choses pour les packages de déclarer les dépendances: 1. construire ce package, 2. installer (premier bâtiment, si nécessaire) de ses dépendances.setup.py
. Aussi, si il a essayé de faire plein de profondeur d'abord et de faire tous les deps avant qu'il ne, il serait coincé si il y avait circulaire de deps. Mais si elle tente de construire ce paquet avant d'installer les dépendances, alors si vous importez votre colis auprès de votresetup.py
, il ne sera pas nécessairement capable d'importer son deps, ou le droit à des versions de ses deps.execfile("myniftyapp/_version.py")
de l'intérieur setup.py plutôt que d'essayer d'analyser le code de version manuellement. Suggéré dans stackoverflow.com/a/2073599/647002 -- discussion, il peut être utile, aussi.1.2.3
) et ensuite de lire que danssetup.py
ainsi que dans votre forfait? (Pas d'analyse est nécessaire dans cette voie...)__version_info__ = tuple(map(int, __version__.split('.')))
pour que.from ._version import __version__
à tirer dans le_version
module de_version.py
dans le projet local et pas une autre flottant autour dans votre environnement.Réécrit 2017-05
Après plus de dix ans d'écriture de code Python et la gestion des différents paquets, je suis venu à la conclusion que le BRICOLAGE, c'est peut-être pas la meilleure approche.
J'ai commencé à utiliser
pbr
paquet pour traiter avec gestion des versions dans mes paquets. Si vous utilisez git comme SCM, il s'adapte à votre flux de travail, comme par magie, la sauvegarde de vos semaines de travail (vous serez surpris par la complexité de la question peut être).À compter d'aujourd'hui pbr est classé #11 le plus utilisé paquet python et l'atteinte de ce niveau ne comprend pas tout de sales tours: a une seule: la fixation d'une commune de l'emballage problème d'une manière très simple.
pbr
en peut plus de l'emballage le fardeau de l'entretien, n'est pas limitée à la production de versions, mais il ne fait pas de vous forcer à adopter l'ensemble de ses prestations.Donc, pour vous donner une idée de à quoi il ressemble à adopter des droits d'obtenteur dans un commit ont un look swiching emballage pour pbr
Probablement vous observé que la version n'est pas stocké dans le repository. Droits d'OBTENTEUR ne le détecte à partir de Git branches et de tags.
Pas besoin de s'inquiéter à propos de ce qui se passe lorsque vous ne disposez pas d'un dépôt git à cause des droits d'obtenteur ne "compiler" et le cache de la version lorsque vous créez un package ou d'installer les applications, alors il n'y a pas d'exécution de la dépendance sur git.
Vieille solution
Ici est la meilleure solution que j'ai vu jusqu'à présent et cela explique aussi pourquoi l':
À l'intérieur de
yourpackage/version.py
:À l'intérieur de
yourpackage/__init__.py
:À l'intérieur de
setup.py
:Si vous connaissez une autre approche qui semble être mieux faites le moi savoir.
from .version import __version__
dans setup.py ainsi?setup.py
est en cours d'exécution - essayez, vous allez obtenir une erreur (ou au moins, j'ai fait :-)).
est danssys.path
par défaut, donc tant queversion
module ne pas avoir de dépendances, c'est une façon d'aller..
répertoire est le répertoire avecsetup.py
, et non pas le répertoire avec leversion
module...python setup.py install
à partir d'un autre répertoire que le package racine, le rapport de recherche pour version.py échouerahere = os.path.abspath(os.path.dirname(__file__))
puisexec(open(os.path.join(here, 'yourpackage/version.py')).read())
. Aussi, n'est-ce pas trouver un besoin relatif à l'importation.pbr
(Python Construire caractère Raisonnable)! Il a l'air très prometteur! Il va nous aider à atteindre sur la façon de rendre l'écosystème plus sûr et plus robuste via des fichiers texte commesetup.cfg
, plutôt que de BRICOLAGE code qui s'exécute dans setup.py qui a pris la PyPI, pip install et la gestion des exigences des emplois beaucoup plus difficile.pbr
pour le contrôle de version?module.__version__
-- en fait, ce droit d'obtenteur n'est automatise la création de ce au moment de la construction et de son entretien lors de l'exécution à partir de git. Si vous utilisez git et balises pour la version ce serait une perte de temps de ne pas bénéficier d'elle. Vrai que le droit d'obtenteur est apparu sur openstack, mais il n'a rien de précis sur ce (sa popularité n'a rien à voir avec openstack). J'espère que l'emballage sur python évoluera donc des droits d'obtenteur ne seraient pas nécessaires.Par le report de la PEP 396 (les Numéros de Version), il y a une proposition de méthode pour ce faire. Il décrit, avec justification, un (certes en option) standard pour les modules à suivre. Voici un extrait:
Si c'est sans doute trop tard, il est un peu plus simple alternative à la réponse précédente:
(Et il serait assez simple de convertir l'auto-incrémentation des portions de numéros de version d'une chaîne à l'aide de
str()
.)Bien sûr, de ce que j'ai vu, les gens ont tendance à utiliser quelque chose comme précédemment mentionné version lors de l'utilisation de
__version_info__
, et en tant que tel magasin comme un n-uplet d'entiers; cependant, je n'arrive pas à voir le point de le faire, car je doute qu'il y a des situations où vous devez effectuer des opérations mathématiques, telles que l'addition et de la soustraction sur des portions de numéros de version pour n'importe quel but, outre la curiosité ou de l'auto-incrémentation (et même alors,int()
etstr()
peut être utilisé assez facilement). (D'un autre côté, il y a la possibilité de quelqu'un d'autre code attend numérique tuple plutôt qu'une chaîne n-uplet et donc défaut.)C'est, bien sûr, de mon propre point de vue, et je serais heureux de faire comme les autres' entrée sur le numérique à l'aide d'un tuple.
Comme shezi m'a rappelé, (lexicale) les comparaisons de chaînes de nombre n'ont pas forcément le même résultat que le numérique directe des comparaisons; les zéros à gauche serait tenu de fournir pour cela. Donc en fin de compte, le stockage
__version_info__
(ou ce qu'il serait appelé) comme un n-uplet de valeurs entières permettrait une plus grande efficacité de la version comparaisons.__version_info__ = (1,2,3)
int()
pour faire une comparaison de la valeur, ou tout simplement faire ce que orip suggéré et stocker les valeurs comme des nombres entiers.__version_info__ = (0, 1, 0) __version__ = '.'.join(map(str, __version_info__))
__version__ = '.'.join(__version_info__)
est que__version_info__ = ('1', '2', 'beta')
deviendra1.2.beta
, pas1.2beta
ou1.2 beta
2 < 10
évalue àTrue
, mais'2' < '10'
évalue àFalse
).setup.py
?Nombre de ces solutions ici ignorer
git
version balises qui signifie que vous devez suivre les version dans de multiples endroits (bad). Je me suis approché de ce, avec les objectifs suivants:git
repogit tag
/push
etsetup.py upload
étapes avec une seule commande qui ne prend pas d'entrées.Comment cela fonctionne:
À partir d'un
make release
de commande, la dernière version après marquage dans le repo git est trouvé et incrémenté. La balise est repoussé àorigin
.La
Makefile
magasins de la version ensrc/_version.py
où il sera lu parsetup.py
et sont également inclus dans le communiqué. Ne pas vérifier_version.py
dans le contrôle de source!setup.py
commande lit la nouvelle version de la chaîne depackage.__version__
.Détails:
Makefile
La
release
cible incrémente toujours la version 3 chiffres, mais vous pouvez utiliser lenext_minor_ver
ounext_major_ver
pour incrémenter les autres chiffres. Les commandes s'appuyer sur laversionbump.py
script qui est vérifié dans la racine de l'opérationversionbump.py
Cela ne le levage lourd manière de traiter et d'incrémenter le numéro de version de
git
.__init__.py
La
my_module/_version.py
fichier est importé dansmy_module/__init__.py
. Mettre statique installer config ici que vous voulez distribué avec votre module.setup.py
La dernière étape est de lire les informations de version de l'
my_module
module.Bien sûr, pour que tout cela fonctionne, vous devez avoir au moins une balise de version dans votre pension pour commencer.
versionbump.py
lorsque nous avons un impressionnant bumpversion forfait pour python.setup.py
de commande._version.py
être suivis avec le contrôle de version?- Je utiliser un fichier JSON dans le package dir. Cela correspond Zooko exigences.
À l'intérieur de
pkg_dir/pkg_info.json
:À l'intérieur de
setup.py
:À l'intérieur de
pkg_dir/__init__.py
:J'ai aussi mis d'autres informations dans
pkg_info.json
, comme l'auteur. J'comme pour l'utilisation de JSON parce que je peux automatiser la gestion des métadonnées.
Également intéressant de noter, c'est que ainsi que
__version__
être un semi-std. en python, donc est__version_info__
qui est un n-uplet, dans les cas simples, vous pouvez simplement faire quelque chose comme:...et vous pouvez obtenir le
__version__
chaîne à partir d'un fichier, ou quoi que ce soit.__version_info__
?__version_info__ = (1, 2, 3)
et__version__ = '.'.join(map(str, __version_info__))
).i
n'a pas de sens,version_num
est un peu longue et ambigu...). J'ai même pris l'existence demap()
en Python comme un indice qu'il devrait être utilisé ici, comme ce que nous devons faire ici, c'est le cas d'utilisation typique demap()
(à utiliser avec une fonction existante)—je ne vois pas beaucoup d'autres usages raisonnables.Il ne semble pas être un moyen standard pour intégrer une chaîne de version dans un paquet python. La plupart des paquets que j'ai vu utiliser une variante de votre solution, c'est à dire eitner
Intégrer la version en
setup.py
et ontsetup.py
générer un module (par exempleversion.py
) ne contenant que des informations de version, qui ont été importées par votre forfait, ouL'inverse: mettre les informations de version dans votre paquet, et l'importation que de définir la version en
setup.py
J'ai aussi vu un autre style:
.VERSION
ne signifie pas que vous n'avez pas à mettre en œuvre__version__
.django
dans le projet?flèche gère d'une façon intéressante.
Maintenant (depuis 2e5031b)
Dans
arrow/__init__.py
:Dans
setup.py
:Avant
Dans
arrow/__init__.py
:Dans
setup.py
:file_text
?pip install -e .
sur une branche de développement ou de quelque chose lors de l'essai. setup.py absolument ne devrait pas compter sur l'importation du package, il est dans le processus de l'installation afin de déterminer les paramètres pour le déploiement. Aïe.Pour ce que ça vaut, si vous utilisez NumPy distutils,
numpy.distutils.misc_util.Configuration
a unmake_svn_version_py()
méthode qui incorpore le numéro de révision à l'intérieur depackage.__svn_version__
dans la variableversion
.À l'aide de
setuptools
etpbr
La meilleure solution que j'ai trouvé pour l'ensemble de la gestion de version est à utiliser
setuptools
avec lepbr
extension. PBR se déplace la plupart des métadonnées de lasetup.py
outils et dans unsetup.cfg
fichier qui est ensuite utilisé comme source pour la plupart des métadonnées, ce qui peut inclure la version.Lors de l'utilisation de Git pour VCS/SCM, cette configuration est encore mieux, car il va tirer dans un grand nombre de métadonnées à partir de Git, de sorte que votre pension peut être votre principale source de vérité pour certains des métadonnées, y compris la version, les auteurs, les changelogs, etc.
setup.py
et unsetup.cfg
fichier de métadonnées.Comme droit d'OBTENTEUR tirez version, l'auteur, le changelog et d'autres informations directement à partir de votre repo git, de sorte que certaines des métadonnées dans
setup.cfg
peuvent être laissés de côté et auto généré à chaque fois qu'une distribution de la création de votre colis (à l'aide desetup.py
)En temps réel version actuelle
setuptools
va tirer la dernière info en temps réel à l'aide desetup.py
:Cela permettra de tirer la dernière version de la
setup.cfg
fichier, ou de le repo git, basé sur le dernier commit qui a été faite et les balises qui existent dans le repo. Cette commande ne permet pas de mettre à jour la version dans un réseau de distribution bien.La mise à jour de la version
Lorsque vous créez une distribution avec
setup.py
(c'est à direpy setup.py sdist
, par exemple), toutes les infos seront extraites et stockées dans la distribution. Essentiellement, cela exécute lasetup.py --version
de commande, puis stocke que les informations de version dans lepackage.egg-info
dossier dans un ensemble de fichiers de distribution du magasin de métadonnées.Vous pouvez accéder aux métadonnées de la génération en cours dans les scripts Python dans le paquet lui-même. Pour la version, par exemple, il y a plusieurs façons de faire ce que j'ai trouvé jusqu'à présent:
Vous pouvez mettre une de ces directement dans votre
__init__.py
pour le package d'extraire les informations de version comme suit, à l'instar de certaines autres réponses:version.py
fichier seulement avec__version__ = <VERSION>
param dans le fichier. Dans lesetup.py
l'importation de fichiers de la__version__
param et mettre sa valeur dans lasetup.py
fichier comme ceci:version=__version__
setup.py
fichier avecversion=<CURRENT_VERSION>
- le CURRENT_VERSION est codé en dur.Car nous ne voulons pas modifier manuellement la version dans le fichier à chaque fois que nous créons une nouvelle balise (prêt à la sortie d'une nouvelle version du package), on peut utiliser la suite..
Je recommande fortement bumpversion paquet. Je l'ai utilisé pendant des années pour incrémenter la version.
commencez par ajouter
version=<VERSION>
à votresetup.py
fichier si vous ne l'avez pas déjà.Vous devez utiliser un petit script comme ça à chaque fois que vous croiserez un version:
Puis ajouter un fichier par repo appelé:
.bumpversion.cfg
:Remarque:
__version__
paramètreversion.py
fichier, comme il a été suggéré dans d'autres posts et mise à jour de la bumpversion fichier comme ceci:[bumpversion:file:<RELATIVE_PATH_TO_VERSION_FILE>]
git commit
ougit reset
tout dans votre pension, sinon vous obtiendrez un sale repo erreur.bumpversion
, sans cela, il ne fonctionnera pas. L'utilisation de la dernière version.version.py
, ou de suivi avecbumpversion
?__version__
param valeur dans le setup.py fichier. Ma solution est utilisée en production et c'est une pratique courante. Note: juste pour être clair, à l'aide de bumpversion dans le cadre d'un script est la meilleure solution, le mettre dans votre CI et il sera en fonctionnement automatique.Si vous utilisez CVS (ou RCS) et qui souhaitent une solution rapide, vous pouvez utiliser:
(Bien sûr, le numéro de révision sera substitué pour vous par CVS.)
Cela vous donne une version imprimable et une version info que vous pouvez utiliser pour vérifier que le module que vous importez a au moins la version attendue:
__version__
pour? Comment incrémenter le numéro de version de cette solution?