Проверка версии модуля Python во время выполнения
Многие сторонние модули Python имеют атрибут, который содержит информацию о версии для модуля (обычно это что-то вроде module.VERSION
или module.__version__
), однако некоторые из них этого не делают.
Частными примерами таких модулей являются libxslt и libxml2.
Мне нужно проверить, что правильная версия этих модулей используется во время выполнения. Есть ли способ сделать это?
Потенциальное решение wold должно быть прочитано в источнике во время выполнения, хеш его, а затем сравнить его с хэшем известной версии, но это противно.
Есть ли лучшие решения?
Ответы
Ответ 1
Я бы держался подальше от хеширования. В используемой версии libxslt может содержаться некоторый тип патча, который не влияет на его использование.
В качестве альтернативы я бы хотел предложить, чтобы вы не проверяли во время выполнения (не знаете, жестко это или нет). Для содержимого python я пишу, что имеет внешние зависимости (сторонние библиотеки), пишу script, который пользователи могут запускать, чтобы проверить их установку python, чтобы проверить, установлены ли соответствующие версии модулей.
Для модулей, у которых нет определенного атрибута "версия", вы можете проверить интерфейсы, которые он содержит (классы и методы), и посмотреть, соответствуют ли они интерфейсу, который они ожидают. Затем в действительном коде, над которым вы работаете, предположите, что сторонние модули имеют интерфейс, который вы ожидаете.
Ответ 2
Используйте pkg_resources. Все, что установлено из PyPI, должно иметь номер версии.
>>> import pkg_resources
>>> pkg_resources.get_distribution("blogofile").version
'0.7.1'
Ответ 3
Некоторые идеи:
- Попробуйте проверить функции, которые существуют или не существуют в ваших необходимых версиях.
- Если функциональных различий нет, проверьте аргументы функции и подписи.
- Если вы не можете понять это из сигнатур функций, настройте некоторые заглушки во время импорта и проверьте их поведение.
Ответ 4
Вы можете использовать
pip freeze
чтобы увидеть установленные пакеты в формате требований.
Ответ 5
Для этого вы можете использовать библиотеку 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
, а не имя модуля, которое предоставляет этот пакет (хотя обычно они совпадают).
Ответ 6
Я нашел довольно ненадежным использование различных доступных инструментов (включая лучший pkg_resources
упомянутый в этом другом ответе), так как большинство из них не охватывает все случаи. Например
- встроенные модули
- модули не установлены, а просто добавлены в путь к Python (например, вашей IDE)
- доступны две версии одного и того же модуля (одна в пути Python заменяет установленную)
Так как нам нужен был надежный способ получить версию любого пакета, модуля или субмодуля, я закончил писать getversion. Это довольно просто использовать:
from getversion import get_module_version
import foo
version, details = get_module_version(foo)
Смотрите документацию для деталей.
Ответ 7
Для модулей, которые не предоставляют __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))