Controllo della versione di un modulo Python in fase di esecuzione


118

Molti moduli Python di terze parti hanno un attributo che contiene le informazioni sulla versione del modulo (di solito qualcosa come module.VERSIONo module.__version__), tuttavia alcuni no.

Esempi particolari di tali moduli sono libxslt e libxml2.

Devo controllare che la versione corretta di questi moduli venga utilizzata in fase di esecuzione. C'è un modo per fare questo?

Una possibile soluzione potrebbe essere quella di leggere nel codice sorgente in fase di esecuzione, sottoporlo a hash e quindi confrontarlo con l'hash della versione conosciuta, ma è sgradevole.

C'è una soluzione migliore?

Risposte:


8

Starei lontano dall'hashing. La versione di libxslt utilizzata potrebbe contenere qualche tipo di patch che non influisce sul suo utilizzo.

In alternativa, vorrei suggerire di non controllare in fase di esecuzione (non so se sia un requisito difficile o meno). Per il materiale Python che scrivo che ha dipendenze esterne (librerie di terze parti), scrivo uno script che gli utenti possono eseguire per controllare la loro installazione di Python per vedere se sono installate le versioni appropriate dei moduli.

Per i moduli che non hanno un attributo "versione" definito, puoi controllare le interfacce che contiene (classi e metodi) e vedere se corrispondono all'interfaccia che si aspettano. Quindi, nel codice effettivo su cui stai lavorando, presumi che i moduli di terze parti abbiano l'interfaccia che ti aspetti.


244

Usa pkg_resources . Qualunque cosa installata da PyPI almeno dovrebbe avere un numero di versione.

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'

8
Notare inoltre che il nome del pacchetto deve essere quello della voce PyPI. Quindi qualcosa come "pkg_resources.get_distribution ('MySQLdb'). Version" non funzionerà ma "pkg_resources.get_distribution ('mysql-python'). Version" lo farà.
Rahul

1
Se stai eseguendo con un nome di file assoluto, pkg_resourcespotresti prendere una versione diversa che ombreggia quella che stai effettivamente eseguendo perché ha una precedenza maggiore sul tuo PYTHONPATHo simile.
tripleee

4
Nel caso qualcuno volesse sapere come creare l' __version__attributo: stackoverflow.com/q/17583443/562769
Martin Thoma

pkg_resourcesil collegamento è un errore 404
gerrit

Per l'elaborazione automatizzata, vedere questa domanda
gerrit

6

Qualche idea:

  1. Prova a verificare la presenza di funzioni che esistono o non esistono nelle versioni necessarie.
  2. Se non ci sono differenze di funzione, ispeziona gli argomenti e le firme della funzione.
  3. Se non riesci a capirlo dalle firme delle funzioni, imposta alcune chiamate stub al momento dell'importazione e controlla il loro comportamento.

I pacchetti dovrebbero specificare la loro versione. Queste idee sono totalmente eccessive per il normale compito (stimato nel 99% dei casi) di controllare una versione.
Zelphir Kaltstahl

2

Puoi usare

pip freeze

per vedere i pacchetti installati nel formato dei requisiti.


1

Puoi usare la importlib_metadatalibreria per questo.

Se sei su python < 3.8, installalo prima con:

pip install importlib_metadata

Poiché python 3.8è incluso nella libreria standard di python.

Quindi, per controllare la versione di un pacchetto (in questo esempio lxml) eseguire:

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

Tieni presente che questo funziona solo per i pacchetti installati da PyPI. Inoltre, è necessario passare un nome di pacchetto come argomento al versionmetodo, piuttosto che un nome di modulo fornito da questo pacchetto (sebbene di solito siano gli stessi).


0

Ho trovato abbastanza inaffidabile utilizzare i vari strumenti disponibili (incluso il migliore pkg_resourcesmenzionato da quest'altra risposta ), poiché la maggior parte di essi non copre tutti i casi. Per esempio

  • moduli integrati
  • moduli non installati ma solo aggiunti al percorso python (ad esempio dal tuo IDE)
  • disponibili due versioni dello stesso modulo (una nel percorso python che sostituisce quella installata)

Poiché avevamo bisogno di un modo affidabile per ottenere la versione di qualsiasi pacchetto, modulo o sottomodulo, ho finito per scrivere getversion . È abbastanza semplice da usare:

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

Vedere la documentazione per i dettagli.


0

Per i moduli che non forniscono __version__quanto segue è brutto ma funziona:

#!/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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.