Перевірте, чи встановлено пакет Python


112

Який хороший спосіб перевірити, чи встановлений пакет під час сценарію Python? Я знаю, що це легко від перекладача, але мені це потрібно зробити в рамках сценарію.

Я думаю, я міг би перевірити, чи є в системі створений під час встановлення каталог, але я відчуваю, що є кращий спосіб. Я намагаюся переконатися, що пакет Skype4Py встановлений, і якщо ні, я його встановлю.

Мої ідеї щодо здійснення перевірки

  • перевірте наявність каталогу в типовому шляху встановлення
  • спробуйте імпортувати пакет, і якщо виняток є кидком, то встановіть пакет

Написання сценарію Python для автоматизації запуску Skype та використання tcpdump для збору пакетних даних, щоб я міг проаналізувати, як функціонує мережа під час конференційного дзвінка.
Кевін

Відповіді:


107

Якщо ви маєте на увазі сценарій 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")

Пітон 3:

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

Пітон 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

1
Якось мені потрібно було використовувати чек if "u'requests'" in installed_packages:із оновленого відповіді, щоб працювати на мене. Вихід print()виробляє це на моєму MacOS пітона:[..., u'pytz', u'requests', ...]
BUJU

1
@ArturBarseghyan Я на Python 2.7.10 (система macOS python) ... насправді мені доведеться використовувати 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')не знайдено. Офіційне ім’я та ім’я, яке показує піп, - з тире, а не крапками. Тому це може бути заплутано з обережністю.
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 —версія" та "$ pip3 показати ім'я пакета", де ви заміните ім'я пакета на потрібний пакет?
Огнен Вукович

Підказка оболонки: ви можете 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

Не зі сценарію, але відмінно підходить для перевірки командного рядка. Спасибі
Jj Rivero

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

клас myError (виняток): pass # або зробіть щось, спробуйте: імпортувати мій модуль, крім 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.