Verificando una versión del módulo de Python en tiempo de ejecución

118

Muchos módulos de Python de terceros tienen un atributo que contiene la información de la versión del módulo (generalmente algo como module.VERSIONo module.__version__), sin embargo, algunos no.

Ejemplos particulares de estos módulos son libxslt y libxml2.

Necesito comprobar que se esté utilizando la versión correcta de estos módulos en tiempo de ejecución. ¿Hay alguna forma de hacer esto?

Una posible solución sería leer el código fuente en tiempo de ejecución, hacer un hash y luego compararlo con el hash de la versión conocida, pero eso es desagradable.

¿Hay mejores soluciones?

Brusco
fuente

Respuestas:

8

Me mantendría alejado del hash. La versión de libxslt que se está utilizando puede contener algún tipo de parche que no afecte su uso.

Como alternativa, me gustaría sugerirle que no verifique en tiempo de ejecución (no sé si ese es un requisito difícil o no). Para las cosas de Python que escribo que tienen dependencias externas (bibliotecas de terceros), escribo un script que los usuarios pueden ejecutar para verificar su instalación de Python para ver si están instaladas las versiones apropiadas de los módulos.

Para los módulos que no tienen un atributo de 'versión' definido, puede inspeccionar las interfaces que contiene (clases y métodos) y ver si coinciden con la interfaz que esperan. Luego, en el código real en el que está trabajando, asuma que los módulos de terceros tienen la interfaz que espera.

Mark Roddy
fuente
244

Utilice pkg_resources . Todo lo que se instale desde PyPI al menos debe tener un número de versión.

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
EnigmaCurry
fuente
8
También tenga en cuenta que el nombre del paquete debe ser el de la entrada PyPI. Entonces, algo como "pkg_resources.get_distribution ('MySQLdb'). Version" no funcionará, pero "pkg_resources.get_distribution ('mysql-python'). Version" sí.
Rahul
1
Si está ejecutando con un nombre de archivo absoluto, es pkg_resourcesposible que elija una versión diferente que sombree la que está ejecutando porque tiene mayor precedencia sobre su versión PYTHONPATHo similar.
tripleee
4
En caso de que alguien quiera saber cómo hacer el __version__atributo: stackoverflow.com/q/17583443/562769
Martin Thoma
pkg_resourcesenlace es un error 404
gerrit
Para el procesamiento automatizado, consulte esta pregunta
gerrit
6

Algunas ideas:

  1. Intente buscar funciones que existan o no existan en sus versiones necesarias.
  2. Si no hay diferencias de funciones, inspeccione los argumentos y firmas de las funciones.
  3. Si no puede averiguarlo a partir de las firmas de funciones, configure algunas llamadas de código auxiliar en el momento de la importación y verifique su comportamiento.
Richard Levasseur
fuente
Los paquetes deben especificar su versión. Estas ideas son totalmente exageradas para la tarea generalmente fácil (se estima en el 99% de los casos) de verificar una versión.
Zelphir Kaltstahl
2

Puedes usar

pip freeze

para ver los paquetes instalados en formato de requisitos.

nos
fuente
1

Puede usar la importlib_metadatabiblioteca para esto.

Si está en python < 3.8, primero instálelo con:

pip install importlib_metadata

Dado que Python 3.8está incluido en la biblioteca estándar de Python.

Luego, para verificar la versión de un paquete (en este ejemplo lxml) ejecute:

>>> from importlib_metadata import version
>>> version('lxml')
'4.3.1'

Tenga en cuenta que esto solo funciona para paquetes instalados desde PyPI. Además, debe pasar un nombre de paquete como argumento del versionmétodo, en lugar de un nombre de módulo que proporciona este paquete (aunque normalmente son los mismos).

Jakub Kukul
fuente
0

Me pareció bastante poco confiable usar las diversas herramientas disponibles (incluida la mejor pkg_resourcesmencionada en esta otra respuesta ), ya que la mayoría de ellas no cubren todos los casos. Por ejemplo

  • módulos incorporados
  • módulos no instalados pero recién agregados a la ruta de Python (por su IDE, por ejemplo)
  • dos versiones del mismo módulo disponibles (una en la ruta de Python que reemplaza a la instalada)

Como necesitábamos una forma confiable de obtener la versión de cualquier paquete, módulo o submódulo, terminé escribiendo getversion . Es bastante simple de usar:

from getversion import get_module_version
import foo
version, details = get_module_version(foo)

Consulte la documentación para obtener más detalles.

smarie
fuente
0

Para los módulos que no proporcionan __version__lo siguiente es feo pero funciona:

#!/usr/bin/env python3.6
import sys
import os
import subprocess
import re

sp = subprocess.run(["pip3", "show", "numpy"], stdout=subprocess.PIPE)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))

o

#!/usr/bin/env python3.7
import sys
import os
import subprocess
import re

sp = subprocess.run(["pip3", "show", "numpy"], capture_output=True)
ver = sp.stdout.decode('utf-8').strip().split('\n')[1]
res = re.search('^Version:\ (.*)$', ver)
print(res.group(1))
phzx_munki
fuente