Идентификация отношения зависимостей для пакетов python, установленных с помощью pip

Когда я делаю зависание в пипе, я вижу большое количество пакетов 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, и я не хочу зависеть от пакета, пока не узнаю больше о том, что вы случайно не удалили его или не обновили.

Ответ 1

Вы можете попробовать 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]

Ответ 2

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

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show был введен в pip версии 1.4rc5

Ответ 3

Как я недавно сказал в hn thread, я рекомендую следующее:

Отметьте 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, заменяемых именами яиц в процессе.
  • Зависимости ваших зависимостей по-прежнему сортируются по алфавиту, поэтому вы напрямую не знаете, какой из них требуется для какого пакета, но на данный момент вам это действительно не нужно.
  • Используйте pip install --no-install <package_name> для указания конкретных требований.
  • Используйте virtualenv, если вы этого не сделаете.

Ответ 4

Вы также можете использовать команду с одной строкой, которая передает пакеты в требованиях к показам pip.

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

Ответ 5

Прежде всего pip freeze отображает все установленные на данный момент пакеты Python, не обязательно используя PIP.

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

Чтобы решить обновление пакетов, я рекомендую использовать файлы требований PIP. Вы можете определить, какие пакеты и версии вам понадобятся, и установить их сразу с помощью установки pip.

Ответ 6

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

#!/usr/bin/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.get_installed_distributions():
        for requirement_package in package.requires():
            requirement_name = requirement_package.project_name
            if requirement_name == target_name:
                package_name = package.project_name
                yield package_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)))

Ответ 7

(обходной путь, а не истинный ответ)

Имела ту же проблему, когда lxml не устанавливался, и мне хотелось знать, кому нужен lxml. Не нужен lxml. Закончено обход проблемы.

  • отметив, куда были помещены пакеты моего сайта.

  • Перейдите туда и рекурсивный grep для импорта (последний grep -invert-match служит для удаления lxml собственных файлов из соображений).

Да, не ответ на вопрос, как использовать pip для этого, но я не получил никакого успеха из предложений здесь, по любой причине.

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