¿Forma estándar de incrustar la versión en el paquete Python?
¿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.py
ya están especificadas. La solución alternativa que encontré fue tenerla import __version__
en mi foo/__init__.py
y luego __version__.py
generarla mediante setup.py
.
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).
Utilizo un solo _version.py
archivo como el "lugar que alguna vez fue canónico" para almacenar información de la versión:
Proporciona un
__version__
atributo.Proporciona la versión de metadatos estándar. Por lo tanto, será detectado por
pkg_resources
otras herramientas que analicen los metadatos del paquete (EGG-INFO y/o PKG-INFO, PEP 0345).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).
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__.py
esta 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.