Verificar uma versão do módulo Python em tempo de execução

118

Muitos módulos Python de terceiros têm um atributo que contém as informações de versão do módulo (geralmente algo como module.VERSIONou module.__version__), mas alguns não.

Exemplos particulares de tais módulos são libxslt e libxml2.

Preciso verificar se a versão correta desses módulos está sendo usada em tempo de execução. Existe uma maneira de fazer isso?

Uma solução potencial seria ler o código-fonte em tempo de execução, fazer um hash e depois compará-lo com o hash da versão conhecida, mas isso é desagradável.

Existe uma solução melhor?

Rude
fonte

Respostas:

8

Eu ficaria longe do hashing. A versão do libxslt que está sendo usada pode conter algum tipo de patch que não afeta seu uso.

Como alternativa, gostaria de sugerir que você não verifique em tempo de execução (não sei se isso é um requisito difícil ou não). Para as coisas de python que escrevo que têm dependências externas (bibliotecas de terceiros), escrevo um script que os usuários podem executar para verificar a instalação de python e ver se as versões apropriadas dos módulos estão instaladas.

Para os módulos que não têm um atributo de 'versão' definido, você pode inspecionar as interfaces que ele contém (classes e métodos) e ver se eles correspondem à interface que esperam. Então, no código real em que você está trabalhando, suponha que os módulos de terceiros tenham a interface que você espera.

Mark Roddy
fonte
244

Use pkg_resources . Qualquer coisa instalada a partir do PyPI, pelo menos, deve ter um número de versão.

>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
EnigmaCurry
fonte
8
Observe também que o nome do pacote deve ser o da entrada PyPI. Portanto, algo como "pkg_resources.get_distribution ('MySQLdb'). Version" não funcionará, mas "pkg_resources.get_distribution ('mysql-python'). Version" sim.
Rahul
1
Se você estiver executando com um nome de arquivo absoluto, pkg_resourcespode escolher uma versão diferente, sombreando aquela que você está realmente executando, porque ela tem precedência superior em seu PYTHONPATHou semelhante.
tripleee
4
Caso alguém queira saber como fazer o __version__atributo: stackoverflow.com/q/17583443/562769
Martin Thoma
pkg_resourceso link é um erro 404
gerrit
Para processamento automatizado, veja esta pergunta
gerrit
6

Algumas ideias:

  1. Tente verificar se há funções existentes ou não nas versões necessárias.
  2. Se não houver diferenças de função, inspecione os argumentos e assinaturas da função.
  3. Se você não conseguir descobrir a partir das assinaturas de função, configure algumas chamadas de stub no momento da importação e verifique seu comportamento.
Richard Levasseur
fonte
Os pacotes devem especificar sua versão. Essas ideias são totalmente exageradas para a tarefa geralmente (estimada em 99% dos casos) fácil de verificar uma versão.
Zelphir Kaltstahl
2

Você pode usar

pip freeze

para ver os pacotes instalados no formato de requisitos.

nos
fonte
1

Você pode usar a importlib_metadatabiblioteca para isso.

Se você estiver em python < 3.8, primeiro instale-o com:

pip install importlib_metadata

Desde o python 3.8está incluído na biblioteca padrão do python.

Em seguida, para verificar a versão de um pacote (neste exemplo lxml), execute:

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

Lembre-se de que isso funciona apenas para pacotes instalados do PyPI. Além disso, você deve passar um nome de pacote como um argumento para o versionmétodo, em vez de um nome de módulo que este pacote fornece (embora geralmente sejam iguais).

Jakub Kukul
fonte
0

Achei pouco confiável usar as várias ferramentas disponíveis (incluindo a melhor pkg_resourcesmencionada por esta outra resposta ), pois a maioria delas não cobre todos os casos. Por exemplo

  • módulos embutidos
  • módulos não instalados, mas apenas adicionados ao caminho python (por seu IDE, por exemplo)
  • duas versões do mesmo módulo disponíveis (uma no caminho python substituindo o instalado)

Como precisávamos de uma maneira confiável de obter a versão de qualquer pacote, módulo ou submódulo, acabei escrevendo getversion . É bastante simples de usar:

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

Consulte a documentação para obter detalhes.

smarie
fonte
0

Para módulos que não fornecem __version__o seguinte é feio, mas 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))

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
fonte