¿Forma estándar de incrustar la versión en el paquete Python?

Resuelto Dimitri Tcaciuc asked hace 15 años • 25 respuestas

¿Existe una forma estándar de asociar una cadena de versión con un paquete de Python de tal manera que pueda hacer lo siguiente?

import foo
print(foo.version)

Me imagino que hay alguna manera de recuperar esos datos sin ninguna codificación adicional, ya que las cadenas menores/mayores setup.pyya están especificadas. La solución alternativa que encontré fue tenerla import __version__en mi foo/__init__.pyy luego __version__.pygenerarla mediante setup.py.

Dimitri Tcaciuc avatar Jan 20 '09 01:01 Dimitri Tcaciuc
Aceptado

No es una respuesta directa a tu pregunta, pero deberías considerar nombrarla __version__, no version.

Esto es casi un cuasi estándar. Muchos módulos de la biblioteca estándar utilizan __version__, y este también se utiliza en muchos módulos de terceros, por lo que es el cuasi estándar.

Generalmente __version__es una cadena, pero a veces también es un flotante o una tupla.

Como menciona S.Lott (¡Gracias!), PEP 8 lo dice explícitamente:

Nombres de Dunder de nivel de módulo

Los "dunders" de nivel de módulo (es decir, nombres con dos guiones bajos al principio y dos al final) como __all__,,, etc. deben colocarse después de la cadena de documentación del módulo, pero antes de cualquier declaración de importación, excepto de __author__importaciones .__version____future__

También debe asegurarse de que el número de versión se ajuste al formato descrito en PEP 440 ( PEP 386, una versión anterior de este estándar).

oefe avatar Jan 19 '2009 21:01 oefe

Utilizo un solo _version.pyarchivo como el "lugar que alguna vez fue canónico" para almacenar información de la versión:

  1. Proporciona un __version__atributo.

  2. Proporciona la versión de metadatos estándar. Por lo tanto, será detectado por pkg_resourcesotras herramientas que analicen los metadatos del paquete (EGG-INFO y/o PKG-INFO, PEP 0345).

  3. No importa su paquete (ni ninguna otra cosa) cuando crea su paquete, lo que puede causar problemas en algunas situaciones. (Consulte los comentarios a continuación sobre los problemas que esto puede causar).

  4. Solo hay un lugar donde se anota el número de versión, por lo que solo hay un lugar para cambiarlo cuando cambia el número de versión y hay menos posibilidades de que se produzcan versiones inconsistentes.

Así es como funciona: el "único lugar canónico" para almacenar el número de versión es un archivo .py, llamado "_version.py" que se encuentra en su paquete Python, por ejemplo en myniftyapp/_version.py. ¡Este archivo es un módulo de Python, pero su setup.py no lo importa! (Eso anularía la característica 3). En cambio, su setup.py sabe que el contenido de este archivo es muy simple, algo como:

__version__ = "3.6.5"

Y entonces tu setup.py abre el archivo y lo analiza, con código como:

import re
VERSIONFILE="myniftyapp/_version.py"
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
if mo:
    verstr = mo.group(1)
else:
    raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))

Luego, su setup.py pasa esa cadena como el valor del argumento "versión" setup(), satisfaciendo así la característica 2.

Para satisfacer la característica 1, puede hacer que su paquete (¡en tiempo de ejecución, no en el momento de configuración!) importe el archivo _version de myniftyapp/__init__.pyesta manera:

from _version import __version__

Aquí hay un ejemplo de esta técnica que he estado usando durante años.

El código de ese ejemplo es un poco más complicado, pero el ejemplo simplificado que escribí en este comentario debería ser una implementación completa.

Aquí hay un código de ejemplo para importar la versión .

Si ve algún problema con este enfoque, hágamelo saber.

Zooko avatar Aug 15 '2011 22:08 Zooko