Vérification d'une version de module Python lors de l'exécution

119

De nombreux modules Python tiers ont un attribut qui contient les informations de version du module (généralement quelque chose comme module.VERSIONou module.__version__), mais certains n'en ont pas.

Des exemples particuliers de tels modules sont libxslt et libxml2.

Je dois vérifier que la version correcte de ces modules est utilisée lors de l'exécution. Y a-t-il un moyen de faire cela?

Une solution potentielle serait de lire la source au moment de l'exécution, de la hacher, puis de la comparer au hachage de la version connue, mais c'est désagréable.

Existe-t-il de meilleures solutions?

Bourru
la source

Réponses:

8

Je resterais loin du hachage. La version de libxslt utilisée peut contenir un type de patch qui n'affecte pas votre utilisation.

Comme alternative, j'aimerais vous suggérer de ne pas vérifier au moment de l'exécution (je ne sais pas si c'est une exigence difficile ou non). Pour les trucs python que j'écris qui ont des dépendances externes (bibliothèques tierces), j'écris un script que les utilisateurs peuvent exécuter pour vérifier leur installation python pour voir si les versions appropriées des modules sont installées.

Pour les modules qui n'ont pas d'attribut 'version' défini, vous pouvez inspecter les interfaces qu'il contient (classes et méthodes) et voir si elles correspondent à l'interface attendue. Ensuite, dans le code réel sur lequel vous travaillez, supposez que les modules tiers ont l'interface que vous attendez.

Mark Roddy
la source
245

Utilisez pkg_resources . Tout ce qui est installé à partir de PyPI au moins doit avoir un numéro de version.

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
ÉnigmeCurry
la source
8
Notez également que le nom du package doit être celui de l'entrée PyPI. Donc quelque chose comme "pkg_resources.get_distribution ('MySQLdb'). Version" ne fonctionnera pas mais "pkg_resources.get_distribution ('mysql-python'). Version" le fera.
Rahul
1
Si vous exécutez avec un nom de fichier absolu, vous pkg_resourcespouvez choisir une version différente de celle que vous utilisez réellement, car elle a une priorité plus élevée sur la vôtre PYTHONPATHou similaire.
tripleee
4
Au cas où quelqu'un voudrait savoir comment créer l' __version__attribut: stackoverflow.com/q/17583443/562769
Martin Thoma
pkg_resourcesle lien est une erreur 404
gerrit
Pour le traitement automatisé, voir cette question
gerrit
6

Quelques idées:

  1. Essayez de vérifier les fonctions qui existent ou n'existent pas dans les versions dont vous avez besoin.
  2. S'il n'y a aucune différence de fonction, inspectez les arguments et les signatures de fonction.
  3. Si vous ne pouvez pas le comprendre à partir des signatures de fonction, configurez des appels de stub au moment de l'importation et vérifiez leur comportement.
Richard Levasseur
la source
Les packages doivent spécifier leur version. Ces idées sont totalement exagérées pour la tâche facile (estimée à 99% des cas) de vérifier une version.
Zelphir Kaltstahl
2

Vous pouvez utiliser

pip freeze

pour voir les packages installés au format des exigences.

nos
la source
1

Vous pouvez utiliser la importlib_metadatabibliothèque pour cela.

Si vous êtes sur python < 3.8, installez-le d'abord avec:

pip install importlib_metadata

Depuis python, 3.8il est inclus dans la bibliothèque standard de python.

Ensuite, pour vérifier la version d'un package (dans cet exemple lxml), exécutez:

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

Gardez à l'esprit que cela ne fonctionne que pour les packages installés à partir de PyPI. En outre, vous devez passer un nom de package comme argument à la versionméthode, plutôt qu'un nom de module fourni par ce package (bien qu'ils soient généralement identiques).

Jakub Kukul
la source
0

J'ai trouvé assez peu fiable d'utiliser les différents outils disponibles (y compris le meilleur pkg_resourcesmentionné par cette autre réponse ), car la plupart d'entre eux ne couvrent pas tous les cas. Par exemple

  • modules intégrés
  • modules non installés mais juste ajoutés au chemin python (par votre IDE par exemple)
  • deux versions du même module disponibles (une en chemin python remplaçant celle installée)

Comme nous avions besoin d'un moyen fiable pour obtenir la version de n'importe quel package, module ou sous-module, j'ai fini par écrire getversion . C'est assez simple à utiliser:

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

Consultez la documentation pour plus de détails.

smarie
la source
0

Pour les modules qui ne fournissent pas __version__ce qui suit est moche mais fonctionne:

#!/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))

ou

#!/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
la source