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?

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.


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'

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.

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.


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).


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.


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))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.