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


118

У багатьох сторонніх модулях Python є атрибут, який містить інформацію про версію модуля (як правило, щось на зразок module.VERSIONабо module.__version__), однак деякі - ні.

Конкретні приклади таких модулів - libxslt та libxml2.

Мені потрібно перевірити, чи правильна версія цих модулів використовується під час виконання. Чи є спосіб це зробити?

Потенційне рішення повинно бути прочитане в джерелі під час виконання, хеш і порівняти його з хешем відомої версії, але це противно.

Чи є кращі рішення?

Відповіді:


8

Я б тримався подалі від хешінгу. Використовувана версія libxslt може містити певний тип виправлення, який не впливає на ваше використання.

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

Для модулів, які не мають визначеного атрибута 'версія', ви можете перевірити інтерфейси, які він містить (класи та методи), і побачити, чи відповідають вони інтерфейсу, який вони очікують. Потім у фактичному коді, над яким ви працюєте, припустіть, що сторонні модулі мають очікуваний інтерфейс.


244

Використовуйте pkg_resources . Все, що встановлено з PyPI, має принаймні мати номер версії.

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

8
Також зауважте, що назва пакета повинна бути назвою запису PyPI. Тож щось на зразок "pkg_resources.get_distribution (" MySQLdb "). Версія" не працюватиме, але "pkg_resources.get_distribution (" mysql-python "). Версія" буде.
Рахул

1
Якщо ви працюєте з абсолютним іменем файлу, pkg_resourcesможливо, виберіть іншу версію, відтіняючи ту, яку ви фактично виконуєте, оскільки вона має більший пріоритет над вашою PYTHONPATHчи подібною.
tripleee

4
Якщо хтось хоче знати, як зробити __version__атрибут: stackoverflow.com/q/17583443/562769
Мартін Тома

pkg_resourcesпосилання - помилка 404
Герріт

Про автоматизовану обробку дивіться у цьому питанні
Герріт

6

Деякі ідеї:

  1. Спробуйте перевірити наявність функцій, які існують або не існують у потрібних версіях.
  2. Якщо відмінностей у функціях немає, перевірте аргументи функції та підписи.
  3. Якщо ви не можете зрозуміти це з підписів функцій, налаштуйте кілька закликів на заглушку під час імпорту та перевірте їх поведінку.

Пакети повинні вказувати їх версію. Ці ідеї є надмірно непростими для зазвичай (приблизно 99% випадків) завдання перевірки версії.
Зельфір Кальтшталь

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.