Проверьте, установлен ли пакет Python


113

Какой хороший способ проверить, установлен ли пакет в скрипте Python? Я знаю, что это легко из интерпретатора, но мне нужно сделать это в скрипте.

Думаю, я мог бы проверить, есть ли в системе каталог, созданный во время установки, но мне кажется, что есть способ получше. Я пытаюсь убедиться, что пакет Skype4Py установлен, а если нет, то установлю.

Мои идеи по выполнению проверки

  • проверьте каталог в типичном пути установки
  • попробуйте импортировать пакет, и если возникнет исключение, установите пакет

Написание сценария Python для автоматизации запуска Skype и использования tcpdump для сбора пакетных данных, чтобы я мог проанализировать, как работает сеть, когда у вас есть конференц-связь.
Кевин

Ответы:


108

Если вы имеете в виду скрипт на Python, просто сделайте что-нибудь вроде этого:

Python 3.3+ использует sys.modules и find_spec :

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

if name in sys.modules:
    print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
    # If you choose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    print(f"{name!r} has been imported")
else:
    print(f"can't find the {name!r} module")

Python 3:

try:
    import mymodule
except ImportError as e:
    pass  # module doesn't exist, deal with it.

Python 2:

try:
    import mymodule
except ImportError, e:
    pass  # module doesn't exist, deal with it.

6
Предупреждение: сегодня у меня была ситуация, когда ошибка ImportError была выброшена внутри самого модуля. Это не должно происходить часто, но помните, что эта проверка не во всех случаях надежна.
Koen Bok

7
Это не только проверка ; он также импортирует его; см. также stackoverflow.com/questions/14050281/…
Хорхе Лейтао

6
Да. Это вообще то, что вам нужно. Вы можете использовать модуль инструментов импорта для более сложной проверки, но в большинстве случаев единственная причина, по которой вы заботитесь о том, установлен ли модуль, - это то, что вы хотите его использовать.
Кристофер,

Это не удастся, если у вас есть другой файл с тем же именем, что и пакет.
Sapphire_Brick

Конечно, но это совсем другая проблема. Если у вас есть два разных модуля или пакета с одинаковыми именами в вашем пути поиска, у вас проблемы.
Кристофер

56

Обновленный ответ

Лучший способ сделать это:

import subprocess
import sys

reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
installed_packages = [r.decode().split('==')[0] for r in reqs.split()]

Результат:

print(installed_packages)

[
    "Django",
    "six",
    "requests",
]

Проверить, requestsустановлено ли:

if 'requests' in installed_packages:
    # Do something

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

Обратите внимание, что предлагаемое решение работает:

  • При использовании pip для установки из PyPI или из любого другого альтернативного источника (например, pip install http://some.site/package-name.zipили любого другого типа архива).
  • При установке вручную с помощью python setup.py install .
  • При установке из системных репозиториев вроде sudo apt install python-requests.

Случаи, когда это может не сработать:

  • При установке в режиме разработки вроде python setup.py develop.
  • При установке в режиме разработки вроде бы pip install -e /path/to/package/source/.

Старый ответ

Лучший способ сделать это:

import pip
installed_packages = pip.get_installed_distributions()

Для pip> = 10.x используйте:

from pip._internal.utils.misc import get_installed_distributions

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

В результате вы получите список pkg_resources.Distributionобъектов. См. В качестве примера следующее:

print installed_packages
[
    "Django 1.6.4 (/path-to-your-env/lib/python2.7/site-packages)",
    "six 1.6.1 (/path-to-your-env/lib/python2.7/site-packages)",
    "requests 2.5.0 (/path-to-your-env/lib/python2.7/site-packages)",
]

Составьте список:

flat_installed_packages = [package.project_name for package in installed_packages]

[
    "Django",
    "six",
    "requests",
]

Проверить, requestsустановлено ли:

if 'requests' in flat_installed_packages:
    # Do something

2
Как упоминалось в другом ответе, возможно, ошибка не обнаружена. Поэтому я думаю, что это должен быть принятый ответ.
Йоррик Слейстер,

1
Этот метод не работает с такими пакетами, как 'json' (возвращает False, если import jsonдействительно работает). В этом случае работает метод ice.nicer.
mountrix 06

1
Как-то мне нужно было использовать проверку if "u'requests'" in installed_packages:из Обновленного ответа, чтобы работать на меня. Вывод print()производит это на моем [..., u'pytz', u'requests', ...]
Buju

1
@ArturBarseghyan Я использую Python 2.7.10 (системный питон macOS) ... на самом деле мне нужно использовать if "requests'"(обратите внимание на одинарную кавычку в конце). вообще не имеет смысла.
Buju

1
Это не отвечает на вопрос: «установлен ли пакет 'x'?». Есть много способов установить пакет без использования pip. Например, вы можете создать и установить пакет из исходников. Этот ответ их не найдет. Ответ от @ ice.nicer по поводу find_spec()верного.
Артур

43

По состоянию на Python 3.3, вы можете использовать find_spec () метод

import importlib.util

# For illustrative purposes.
package_name = 'pandas'

spec = importlib.util.find_spec(package_name)
if spec is None:
    print(package_name +" is not installed")

4
Чистый и простой, лучший ответ здесь. Для этого нужно больше голосов.
Дэвид Паркс

5
Быть осторожен. Если имя пакета содержит тире, find_spec () не сможет его найти, если вы не используете точки. Пример: importlib.util.find_spec('google-cloud-logging')ничего не находит, пока importlib.util.find_spec('google.cloud.logging')не найдено. Официальное название и название, которое показывает pip, написано тире, а не точками. Может сбивать с толку, поэтому используйте с осторожностью.
dwich

27

Если вы хотите получить чек с терминала, вы можете запустить

pip3 show package_name

и если ничего не возвращается, пакет не установлен.

Если, возможно, вы хотите автоматизировать эту проверку, чтобы, например, вы могли установить ее в случае ее отсутствия, в вашем сценарии bash может быть следующее:

pip3 show package_name 1>/dev/null #pip for Python 2
if [ $? == 0 ]; then
   echo "Installed" #Replace with your actions
else
   echo "Not Installed" #Replace with your actions, 'pip3 install --upgrade package_name' ?
fi

Это кажется отличным, но мне всегда возвращается «Не установлено». Зачем?
Elliptica

Можете ли вы поделиться выводом «$ pip3 —version» и «$ pip3 show package_name», где вы заменяете package_name на желаемый пакет?
Ognjen Vukovic

Совет оболочки: вы можете использовать ifдля непосредственного тестирования успешной команды:if pip3 show package_name 1>/dev/null; then ...
MestreLion

6

Как продолжение этого ответа :

Для Python 2. * pip show <package_name>будет выполнять ту же задачу.

Например pip show numpy, вернет следующее или подобное:

Name: numpy
Version: 1.11.1
Summary: NumPy: array processing for numbers, strings, records, and objects.
Home-page: http://www.numpy.org
Author: NumPy Developers
Author-email: numpy-discussion@scipy.org
License: BSD
Location: /home/***/anaconda2/lib/python2.7/site-packages
Requires: 
Required-by: smop, pandas, tables, spectrum, seaborn, patsy, odo, numpy-stl, numba, nfft, netCDF4, MDAnalysis, matplotlib, h5py, GridDataFormats, dynd, datashape, Bottleneck, blaze, astropy

Не из сценария, но отлично подходит для проверки командной строки. Спасибо
Джей Джей Риверо

3

Вы можете использовать модуль pkg_resources из setuptools. Например:

import pkg_resources

package_name = 'cool_package'
try:
    cool_package_dist_info = pkg_resources.get_distribution(package_name)
except pkg_resources.DistributionNotFound:
    print('{} not installed'.format(package_name))
else:
    print(cool_package_dist_info)

Обратите внимание, что есть разница между модулем python и пакетом python. Пакет может содержать несколько модулей, и имена модулей могут не совпадать с именем пакета.



1

Я хотел бы добавить к этой теме свои мысли / выводы. Я пишу скрипт, который проверяет все требования для индивидуальной программы. Также есть много проверок с модулями python.

Есть небольшая проблема с

try:
   import ..
except:
   ..

решение. В моем случае вызывается один из модулей python python-nmap, но вы импортируете его с помощьюimport nmap несоответствием имен и, как вы видите. Поэтому тест с вышеуказанным решением возвращает ложный результат, и он также импортирует модуль при попадании, но, возможно, нет необходимости использовать много памяти для простого теста / проверки.

Я также обнаружил, что

import pip
installed_packages = pip.get_installed_distributions()

installed_packagesбудет только пакет, установленный с помощью pip . В моей системе pip freezeвозвращается через 40модули Python, а installed_packagesесть только1 тот, который я установил вручную (python-nmap).

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

Решение, которое сработало для меня. Он основан на этом ответе Как проверить, существует ли модуль python без его импорта

from imp import find_module

def checkPythonmod(mod):
    try:
        op = find_module(mod)
        return True
    except ImportError:
        return False

ПРИМЕЧАНИЕ: это решение также не может найти модуль по имени python-nmap, я должен использовать nmapвместо этого (легко жить), но в этом случае модуль вообще не будет загружен в память.


0

Если вы хотите, чтобы ваш скрипт установил недостающие пакеты и продолжил работу, вы можете сделать что-то вроде этого (на примере модуля krbV в пакете python-krbV):

import pip
import sys

for m, pkg in [('krbV', 'python-krbV')]:
    try:
        setattr(sys.modules[__name__], m, __import__(m))
    except ImportError:
        pip.main(['install', pkg])
        setattr(sys.modules[__name__], m, __import__(m))

0

Быстрый способ - использовать инструмент командной строки python . Просто введите import <your module name> . Если модуль отсутствует, вы увидите сообщение об ошибке.

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
>>> import sys
>>> import jocker
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named jocker
$

0

Хммм ... ближе всего к удобному ответу я использовал командную строку, чтобы попробовать импорт. Но я предпочитаю даже этого избегать.

Как насчет замораживания пипса | grep pkgname '? Я попробовал, работает хорошо. Он также показывает, какая у него версия и установлена ​​ли она в режиме контроля версий (установить) или доступна для редактирования (разработка).


0

class myError (исключение): пройти # или сделать что-нибудь попробовать: импортировать mymodule, кроме ImportError как e: поднять myError («произошла ошибка»)



0

Я хотел бы прокомментировать ответ @ ice.nicer, но не могу, так что ... моим наблюдениям, пакеты с дефисами сохраняются с подчеркиванием, а не только с точками, как указано в комментарии @dwich

Например, да pip3 install sphinx-rtd-theme, но:

  • importlib.util.find_spec(sphinx_rtd_theme) возвращает объект
  • importlib.util.find_spec(sphinx-rtd-theme) не возвращает None
  • importlib.util.find_spec(sphinx.rtd.theme) вызывает ModuleNotFoundError

Более того, некоторые имена полностью изменены. Например, вы это делаете, pip3 install pyyamlно он сохраняется просто какyaml

Я использую python3.8



-1

Перейти к варианту №2. Если ImportErrorвыброшено, то пакет не установлен (или не установлен sys.path).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.