203 votes

Comment puis-je obtenir la version définie dans setup.py (setuptools) dans mon paquet ?

Comment pourrais-je obtenir la version définie dans setup.py de mon paquet (pour --version ou à d'autres fins) ?

3 votes

Je pense que c'est à peu près la même question que stackoverflow.com/questions/458550/ .

308voto

pjeby Points 3228

Interroger la chaîne de version de la distribution déjà installée

Pour récupérer la version à l'intérieur de votre paquet au moment de l'exécution (ce que votre question semble demander en fait), vous pouvez utiliser :

import pkg_resources  # part of setuptools
version = pkg_resources.require("MyProject")[0].version

Stocker la chaîne de version pour l'utiliser pendant l'installation

Si vous voulez faire l'inverse (ce qui semble être ce que les autres auteurs de la réponse ici semblent avoir pensé que vous demandiez), mettez la chaîne de version dans un fichier séparé et lisez le contenu de ce fichier dans setup.py .

Vous pouvez créer une version.py dans votre paquetage avec un fichier __version__ puis le lire à partir de setup.py en utilisant execfile('mypackage/version.py') de manière à ce qu'il fixe __version__ dans l'espace de noms setup.py.

Avertissement sur une condition de course pendant l'installation

Au fait, N'IMPORTEZ PAS votre paquet à partir de votre setup.py comme suggéré dans une autre réponse ici : cela semblera fonctionner pour vous (parce que vous avez déjà les dépendances de votre paquet installées), mais cela fera des ravages pour les nouveaux utilisateurs de votre paquet, car ils ne seront pas en mesure d'installer votre paquet sans installer manuellement les dépendances d'abord.

1 votes

C'est tout simplement la meilleure réponse ici : la meilleure façon est d'utiliser execfile si vous avez besoin de setup.py pour obtenir la version de votre paquet.

3 votes

execfile fonctionne très bien... mais (malheureusement) ne fonctionne pas avec Python 3.

13 votes

... OK, pour Python 2 y 3 utilisation with open('mypackage/version.py') as f: exec(f.read()) à la place de execfile('mypackage/version.py') . (De stackoverflow.com/a/437857/647002 )

25voto

Ned Batchelder Points 128913

La meilleure technique consiste à définir __version__ dans votre code produit, puis importez-le dans setup.py à partir de là. Cela vous donne une valeur que vous pouvez lire dans votre module en cours d'exécution, et vous n'avez qu'un seul endroit pour la définir.

Les valeurs dans setup.py ne sont pas installées, et setup.py ne reste pas en place après l'installation.

Ce que j'ai fait (par exemple) dans coverage.py :

# coverage/__init__.py
__version__ = "3.2"

# setup.py
from coverage import __version__

setup(
    name = 'coverage',
    version = __version__,
    ...
    )

MISE À JOUR (2017) : coverage.py ne s'importe plus lui-même pour obtenir la version. Importer votre propre code peut le rendre désinstallable, parce que votre code produit va essayer d'importer des dépendances, qui ne sont pas encore installées, parce que setup.py est ce qui les installe.

0 votes

+1 C'est ce que j'utilise. Je ne comprends pas pourquoi @pjeby est si opposé à cette méthode. Si vous utilisez "from module import version" et que la version est spécifiée en haut de la source, il ne devrait tirer que cette valeur de la source, peu importe si le fichier source est cassé (ou s'il manque des dépendances).

4 votes

@Evan : Je ne suis pas sûr de ce que vous voulez dire par "ne tirer que cette valeur de la source". Si le fichier avec __version__ si elle est brisée d'une manière ou d'une autre, votre importation le sera aussi. Python ne sait pas comment interpréter uniquement les déclarations que vous voulez. @pjeby a raison : si votre module a besoin d'importer d'autres modules, il se peut qu'ils ne soient pas encore installés, et ce sera chaotique. Cette technique fonctionne si vous faites attention à ce que l'importation ne crée pas une longue chaîne d'autres importations.

1 votes

Ned Batchelder Je suis presque sûr que, si vous mettez la version avant toute importation dans le fichier source et seulement dans un 'from module import version', il ne lxera pas plus du fichier source que nécessaire. De plus, qui va publier du code cassé ? Si le paquet a besoin de dépendances, utilisez setuptools ou attendez la sortie de distutils2 plus tard dans l'année.

19voto

jathanism Points 15208

Votre question est un peu vague, mais je pense que ce que vous demandez est comment le spécifier.

Vous devez définir __version__ comme ça :

__version__ = '1.4.4'

Et vous pourrez alors confirmer que setup.py connaît la version que vous venez de spécifier :

% ./setup.py --version
1.4.4

9voto

Gringo Suave Points 5985

Je n'étais pas satisfait de ces réponses... je ne voulais pas avoir besoin de setuptools, ni faire un module séparé pour une seule variable, alors j'ai trouvé celles-ci.

Pour quand vous êtes sûr que le module principal est dans le style pep8 et qu'il le restera :

version = '0.30.unknown'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            _, _, version = line.replace("'", '').split()
            break

Si vous voulez être très prudent et utiliser un vrai analyseur syntaxique :

import ast
version = '0.30.unknown2'
with file('mypkg/mymod.py') as f:
    for line in f:
        if line.startswith('__version__'):
            version = ast.parse(line).body[0].value.s
            break

setup.py est en quelque sorte un module jetable, ce n'est donc pas un problème s'il est un peu laid.


Mise à jour : il est amusant de constater que je me suis éloigné de cette méthode ces dernières années et que j'ai commencé à utiliser un fichier séparé dans le paquet appelé meta.py . J'y ai mis beaucoup de méta-données que je pourrais vouloir modifier fréquemment. Donc, pas seulement pour une valeur.

0 votes

+1. Il est relativement simple, conserve le numéro de version à un seul endroit, ne nécessite pas un fichier séparé pour le contenir et n'impose pas les dépendances d'importation du module python sur setup.py. Je ne m'embêterais même pas avec le gestionnaire de contexte dans un programme aussi éphémère que setup.py.

0 votes

Much plus agréable que l'utilisation de regex, merci. Vous pouvez également utiliser ast.get_docstring() avec quelques .split('\n')[0].strip() etc. pour remplir automatiquement description de la source. Une chose de moins à synchroniser

5voto

Zooko Points 742

Créez un fichier dans votre arbre des sources, par exemple dans yourbasedir/yourpackage/_version.py . Faites en sorte que ce fichier ne contienne qu'une seule ligne de code, comme ceci :

__version__ = "1.1.0-r4704"

Puis dans votre setup.py, ouvrez ce fichier et récupérez le numéro de version comme ceci :

verstr = "unknown"
try:
    verstrline = open('yourpackage/\_version.py', "rt").read()
except EnvironmentError:
    pass # Okay, there is no version file.
else:
    VSRE = r"^\_\_version\_\_ = \['\\"\](\[^'\\"\]\*)\['\\"\]"
    mo = re.search(VSRE, verstrline, re.M)
    if mo:
        verstr = mo.group(1)
    else:
        raise RuntimeError("unable to find version in yourpackage/\_version.py")

Enfin, en yourbasedir/yourpackage/__init__.py Importez _version comme ceci :

\_\_version\_\_ = "unknown"
try:
    from \_version import \_\_version\_\_
except ImportError:
    # We're running in a tree that doesn't have a \_version.py, so we don't know what our version is.
    pass

Un exemple de code qui fait cela est le paquet "pyutil" que je maintiens. (Voir PyPI ou recherche google -- stackoverflow m'interdit d'inclure un hyperlien vers celui-ci dans cette réponse).

@pjeby a raison de dire que vous ne devez pas importer votre paquet depuis son propre setup.py. Cela fonctionnera lorsque vous le testerez en créant un nouvel interpréteur Python et en exécutant setup.py dans celui-ci en premier lieu : python setup.py mais il y a des cas où cela ne fonctionne pas. C'est parce que import youpackage ne signifie pas qu'il faut lire le répertoire de travail actuel pour y trouver un répertoire nommé "yourpackage", mais qu'il faut chercher dans le répertoire courant sys.modules pour une clé "yourpackage" et ensuite pour faire diverses choses si elle n'est pas là. Ainsi, cela fonctionne toujours lorsque vous faites python setup.py parce que vous avez un nouveau, vide sys.modules mais cela ne fonctionne pas en général.

Par exemple, que se passe-t-il si py2exe exécute votre setup.py dans le cadre du processus d'empaquetage d'une application ? J'ai vu un cas comme celui-ci où py2exe mettait un numéro de version erroné sur un paquet parce que le paquet obtenait son numéro de version à partir de import myownthing dans son setup.py, mais une version différente de ce paquet avait été précédemment importée lors de l'exécution de py2exe. De même, que se passe-t-il si setuptools, easy_install, distribute ou distutils2 essaie de construire votre paquet dans le cadre d'un processus d'installation d'un autre paquet qui dépend du vôtre ? Le fait que votre paquet soit importable au moment où son setup.py est évalué, qu'une version de votre paquet ait déjà été importée au cours de la vie de cet interpréteur Python, que l'importation de votre paquet nécessite l'installation préalable d'autres paquets ou qu'elle ait des effets secondaires, peut modifier les résultats. J'ai eu plusieurs fois l'occasion d'essayer de réutiliser des paquets Python, ce qui a posé des problèmes à des outils comme py2exe et setuptools, car leur setup.py importe le paquet lui-même afin de trouver son numéro de version.

D'ailleurs, cette technique se marie bien avec les outils permettant de créer automatiquement le fichier yourpackage/_version.py pour vous, par exemple en lisant votre historique de contrôle de révision et en écrivant un numéro de version basé sur la balise la plus récente dans l'historique de contrôle de révision. Voici un outil qui fait cela pour darcs : http://tahoe-lafs.org/trac/darcsver/browser/trunk/README.rst et voici un extrait de code qui fait la même chose pour git : http://github.com/warner/python-ecdsa/blob/0ed702a9d4057ecf33eea969b8cf280eaccd89a1/setup.py#L34

1 votes

Pas besoin d'analyser le fichier setup.py. Importez simplement ce fichier python et utilisez version . Il n'y a pas d'effets secondaires de l'importation car c'est le seul contenu de ce fichier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X