Проверка версии модуля Python во время выполнения


119

Многие сторонние модули Python имеют атрибут, содержащий информацию о версии для модуля (обычно что-то вроде module.VERSIONили module.__version__), однако у некоторых нет.

Конкретными примерами таких модулей являются libxslt и libxml2.

Мне нужно проверить, что правильная версия этих модулей используется во время выполнения. Есть ли способ сделать это?

Потенциальным решением было бы прочитать исходный код во время выполнения, хэшировать его, а затем сравнить с хешем известной версии, но это неприятно.

Есть ли лучшие решения?

Ответы:


8

Я бы воздержался от хеширования. Используемая версия libxslt может содержать какой-либо тип патча, который не влияет на ваше использование.

В качестве альтернативы я хотел бы предложить вам не проверять во время выполнения (не знаю, является ли это жестким требованием или нет). Для материала python, который я пишу, который имеет внешние зависимости (сторонние библиотеки), я пишу сценарий, который пользователи могут запускать, чтобы проверить свою установку python, чтобы увидеть, установлены ли соответствующие версии модулей.

Для модулей, у которых нет определенного атрибута «версия», вы можете проверить интерфейсы, которые он содержит (классы и методы), и посмотреть, соответствуют ли они интерфейсу, который они ожидают. Затем в фактическом коде, над которым вы работаете, предположите, что сторонние модули имеют интерфейс, который вы ожидаете.


245

Используйте pkg_resources . Все, что установлено из PyPI, должно иметь как минимум номер версии.

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

8
Также обратите внимание, что имя пакета должно соответствовать записи PyPI. Так что что-то вроде «pkg_resources.get_distribution ('MySQLdb'). Version» не будет работать, но «pkg_resources.get_distribution ('mysql-python'). Version» будет.
Рахул

1
Если вы работаете с абсолютным именем файла, вы pkg_resourcesможете выбрать другую версию, дублирующую ту, которую вы действительно используете, потому что она имеет более высокий приоритет над вашей PYTHONPATHили аналогичной.
Tripleee

4
На случай, если кто-то захочет узнать, как сделать __version__атрибут: stackoverflow.com/q/17583443/562769
Мартин Тома

pkg_resourcesссылка - ошибка 404
gerrit

Информацию об автоматической обработке см. В этом вопросе
gerrit

6

Некоторые идеи:

  1. Попробуйте проверить функции, которые существуют или не существуют в необходимых вам версиях.
  2. Если различий в функциях нет, проверьте аргументы и подписи функций.
  3. Если вы не можете понять это по сигнатурам функций, настройте несколько вызовов-заглушек во время импорта и проверьте их поведение.

В пакетах должна быть указана их версия. Этих идей совершенно нет для обычной (по оценкам 99% случаев) простой задачи проверки версии.
Zelphir Kaltstahl

2

Ты можешь использовать

pip freeze

чтобы увидеть установленные пакеты в формате требований.


1

Вы можете использовать importlib_metadataдля этого библиотеку.

Если вы используете python < 3.8, сначала установите его с помощью:

pip install importlib_metadata

Начиная с python, 3.8он включен в стандартную библиотеку python.

Затем, чтобы проверить версию пакета (в этом примере lxml), выполните:

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

Имейте в виду, что это работает только для пакетов, установленных из PyPI. Кроме того, вы должны передать имя пакета в качестве аргумента versionметоду, а не имя модуля, предоставляемого этим пакетом (хотя обычно они одинаковы).


0

Я счел довольно ненадежным использовать различные доступные инструменты (в том числе лучший, pkg_resourcesупомянутый в этом другом ответе ), поскольку большинство из них не охватывают все случаи. Например

  • встроенные модули
  • модули не установлены, а просто добавлены в путь Python (например, вашей IDE)
  • доступны две версии одного и того же модуля (одна в пути Python заменяет установленную)

Поскольку нам нужен был надежный способ получить версию любого пакета, модуля или подмодуля, я в итоге написал getversion . Использовать довольно просто:

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

Подробности смотрите в документации .


0

Для модулей, которые не предоставляют __version__следующее некрасиво, но работает:

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

или

#!/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))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.