Визначення залежності залежності для пакетів python, встановлених за допомогою pip


151

Коли я роблю заморожування піп, я бачу велику кількість пакетів Python, які я не встановив явно, наприклад

$ pip freeze
Cheetah==2.4.3
GnuPGInterface==0.3.2
Landscape-Client==11.01
M2Crypto==0.20.1
PAM==0.4.2
PIL==1.1.7
PyYAML==3.09
Twisted-Core==10.2.0
Twisted-Web==10.2.0
(etc.)

Чи є спосіб, щоб я визначив, чому pip встановлював саме ці залежні пакети? Іншими словами, як я можу визначити батьківський пакет, який мав ці пакети як залежності?

Наприклад, я можу захотіти використовувати Twisted, і я не хочу залежати від пакета, доки я не дізнаюся більше про те, щоб випадково його не видалити чи оновити.

Відповіді:


180

Ви можете спробувати pipdeptree, який відображає залежності як структуру дерева, наприклад:

$ pipdeptree
Lookupy==0.1
wsgiref==0.1.2
argparse==1.2.1
psycopg2==2.5.2
Flask-Script==0.6.6
  - Flask [installed: 0.10.1]
    - Werkzeug [required: >=0.7, installed: 0.9.4]
    - Jinja2 [required: >=2.4, installed: 2.7.2]
      - MarkupSafe [installed: 0.18]
    - itsdangerous [required: >=0.21, installed: 0.23]
alembic==0.6.2
  - SQLAlchemy [required: >=0.7.3, installed: 0.9.1]
  - Mako [installed: 0.9.1]
    - MarkupSafe [required: >=0.9.2, installed: 0.18]
ipython==2.0.0
slugify==0.0.1
redis==2.9.1

Щоб запустити його:

pip install pipdeptree


EDIT: як зазначає @Esteban у коментарях, ви також можете перелічити дерево у зворотному -rабо для одного пакету, -p <package_name>щоб знайти, який встановлений Werkzeug ви можете запустити:

$ pipdeptree -r -p Werkzeug
Werkzeug==0.11.15
  - Flask==0.12 [requires: Werkzeug>=0.7]

6
Я вважаю, щоб повністю відповісти на питання @mark, яке вам потрібно буде запустити: pipdeptree -r "Показує дерево залежності у зворотному порядку, тобто підзалежності перераховані зі списком пакетів, які потребують їх під ними."
Естебан

Як ви можете переглянути зворотне дерево для всіх пакетів PyPi, не тільки локально встановлених пакетів?
Тійме

2
pipdeptreeце здорово. На жаль, не враховується залежність для пакунків, встановлених conda: наприклад, в conda env, де matplotlibі numpyбули встановлені за допомогою pip, але scipyбуло встановлено за допомогою conda, scipyвиявляється в pipdeptree як не має строків і не залежних (також pip show scipyне показує вимоги).
djvg

@Dennis Я не пробував цього, але це може спрацювати для conda github.com/rvalieris/conda-tree
djsutho

1
Щоб використовувати це у віртуальному середовищі, вам потрібно зробити python -m pipdeptreeінакше (навіть коли виконуваний файл встановлений у virtualenv), він перераховує лише системні залежності.
Зім

81

pip showКоманда покаже , які пакунки необхідні для зазначеного пакета (зверніть увагу , що зазначений пакет повинен бути вже встановлено):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show був представлений у pip-версії 1.4rc5


1
pip showбув представлений у версії 1.4rc5, і присутній у (поточному стані написання) 1.4.1
drevicko

10
Це не відповідає точно на моє запитання, оскільки воно показує дітям (залежності) для певного пакету, а не батьків. Але досить просто злити щось разом, щоб перевірити залежності кожного пакету, використовуючи цю команду. Так, наприклад, я міг визначити, для якого встановленого пакета потрібен PyYAML.
Марк Чакерян

4
Згідно з моїм попереднім коментарем, ця команда оболонки скидає всі залежності для кожного з моїх встановлених пакетів: $ pip freeze | grep -v "\ -e" | sed s /\=\=.*// | awk 'system ("pip show" $ 1) "
Марк Чакерян

Оновлена ​​версія сценарію з мого попереднього коментаря pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ - але, здається, тепер pipdeptree є кращим рішенням.
Марк Чакерян

14

Як я нещодавно сказав у темі hn , я рекомендую наступне:

Майте коментований requirements.txtфайл із вашими основними залежностями:

## this is needed for whatever reason
package1

Встановіть ваші залежності: pip install -r requirements.txt. Тепер ви отримуєте повний список своїх залежностей за допомогою pip freeze -r requirements.txt:

## this is needed for whatever reason
package1==1.2.3

## The following requirements were added by pip --freeze:
package1-dependency1==1.2.3
package1-dependency1==1.2.3

Це дозволяє зберегти вашу файлову структуру з коментарями, добре відокремлюючи свої залежності від залежностей ваших залежностей. Таким чином у вас буде набагато приємніше проводити день, коли потрібно видалити одну з них :)

Зверніть увагу на наступне:

  • Ви можете мати чистий requirements.rawз контролем версій, щоб відновити повну requirements.txt.
  • Слідкуйте за тим, щоб git urls замінювались іменами яєць.
  • Залежності ваших залежностей все ще в алфавітному порядку сортуються, тому ви не знаєте безпосередньо, який саме був потрібний для якого пакета, але в цей момент вам це справді не потрібно.
  • Використовуйте pip install --no-install <package_name>для переліку конкретних вимог.
  • Використовуйте virtualenv, якщо цього не зробите.

1
Я просто не розумію, чому це pip freeze -r requirements.txtшироко не використовується. Дуже корисно для підтримки залежностей та субзалежностей.
Penkey Suresh

1
незначна примітка: pip installбільше не підтримує --no-install.
ryan

7

Ви також можете використовувати команду з одним рядком, яка передає пакети вимогам, щоб показати pip.

cut -d'=' -f1 requirements.txt | xargs pip show

1
Як правило, ви не можете, оскільки формат вимог.txt є складнішим, ніж <package_name>==<package_version>.
Пьотр Доброгост

3

Насамперед pip freezeвідображає всі встановлені в даний час пакети Python, не обов'язково використовуючи PIP.

По-друге, пакети Python містять інформацію про залежні пакунки, а також про необхідні версії . Ви можете побачити залежності конкретного pkg, використовуючи описані тут методи . Коли ви оновлюєте пакет, сценарій установки, як PIP, буде обробляти оновлення залежностей для вас.

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


3

Використовуйте pipupgrade !

$ pip install pipupgrade
$ pipupgrade --format tree --all --check

pipupgrade відображає графік залежності та виділяє кожен пакет для можливого оновлення (на основі семантичної версії). Він також досить сильно відображає конфліктні дитячі залежності. pipupgradeтакож забезпечує оновлення пакетів, наявних у кількох середовищах Python. Сумісний з Python2.7 +, Python3.4 + та pip9 +, pip10 +, pip18 +, pip19 +.

введіть тут опис зображення


1

(вирішення, не вірна відповідь)

Була така ж проблема, що lxml не встановлюється, і я хочу знати, кому потрібен lxml. Не кому потрібен lxml . Закінчилося обходом проблеми на.

  1. зазначивши, де розміщувались пакети мого сайту.

  2. перейдіть туди та рекурсивні grep для імпорту (остання grep's --invert-match служить для видалення власних файлів lxml з розгляду).

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

 site-packages me$ egrep -i --include=*.py  -r -n lxml . | grep import | grep --invert-match /lxml/

1

Я написав швидкий сценарій, щоб вирішити цю проблему. Наступний сценарій відображатиме батьківські (залежні) пакунки для будь-якого даного пакету. Таким чином, ви можете бути впевнені, що безпечно оновити чи встановити будь-який конкретний пакет. Його можна використовувати наступним чином:dependants.py PACKAGENAME

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Find dependants of a Python package"""

import logging
import pip
import pkg_resources
import sys

__program__ = 'dependants.py'


def get_dependants(target_name):
    for package in pip._internal.utils.misc.get_installed_distributions():
        for requirement_package in package.requires():
            requirement_name = requirement_package.project_name
            if requirement_name == target_name:
                yield package.project_name


# configure logging
logging.basicConfig(format='%(levelname)s: %(message)s',
                    level=logging.INFO)

try:
    target_name = sys.argv[1]
except IndexError:
    logging.error('missing package name')
    sys.exit(1)

try:
    pkg_resources.get_distribution(target_name)
except pkg_resources.DistributionNotFound:
    logging.error("'%s' is not a valid package", target_name)
    sys.exit(1)

print(list(get_dependants(target_name)))

Це більше не працює, оскільки get_installed_distributions()метод більше не доступний. github.com/pypa/pip/isissue/5243
Філ Гіфорд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.