识别与pip一起安装的python软件包的依赖关系


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,并且在我不了解不意外卸载或升级它之前,不要依赖于软件包。

Answers:


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


编辑:正如@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 “以相反的方式显示依赖关系树,即子依赖关系与需要它们的软件包列表一起列出。”
Esteban

您如何查看所有PyPi软件包的逆向树,而不仅仅是本地安装的软件包?
Tijme

2
pipdeptree是很棒的。不幸的是,它似乎没有考虑到conda安装的软件包的依赖关系:例如,在conda env中使用pip安装matplotlibnumpy安装,但scipy使用scipyconda 安装,在pipdeptree中显示为没有依赖关系,也没有依赖关系(也pip show scipy显示为no要求)。
djvg

@Dennis我还没有尝试过,但这可能适用于conda github.com/rvalieris/conda-tree
djsutho

1
要在虚拟环境中使用此功能,您需要执行python -m pipdeptree其他操作(即使将可执行文件安装到virtualenv中)也仅列出系统依赖性。
Zim

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。
Mark Chackerian 2014年

4
根据我之前的评论,此shell命令将转储我安装的每个软件包的所有依赖项:grep -v“ \ -e” | sed s /\=\=.*// |
awk'system

我之前的评论中的脚本的更新版本是pip freeze | grep -v "\-e" | sed s/\=\=.*// | awk 'system("pip show " $1)' | grep -E '^(Name:|Requires:)' | sed s/Name:/\\\nName:/ -但看来pipdeptree现在是更好的解决方案。
Mark Chackerian '17

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 url在此过程中被鸡蛋名称替换。
  • 依存关系的依依关系依字母顺序排列,因此您不直接知道哪个软件包需要哪个依存关系,但此时您实际上并不需要它。
  • 使用pip install --no-install <package_name>到表的具体要求。
  • 如果不使用,请使用virtualenv

1
我只是不明白为什么它pip freeze -r requirements.txt没有被广泛使用。对于维护依赖性和子依赖性非常有用。
Penkey Suresh

1
小提示:pip install不再支持--no-install
瑞安

7

您也可以使用一条命令来将需求中的程序包通过管道传输到pip show。

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

1
通常您不能这样做,因为requirements.txt的格式比更为复杂<package_name>==<package_version>
Piotr Dobrogost '16

3

首先pip freeze显示所有当前安装的Python软件包,不一定使用PIP。

其次,Python软件包确实包含有关依赖软件包以及所需版本的信息。您可以使用此处介绍的方法查看特定pkg的依赖性。升级软件包时,安装程​​序脚本(如PIP)将为您处理依赖项的升级。

为了解决软件包的更新问题,我建议使用PIP要求文件。您可以定义所需的软件包和版本,然后使用pip install一次安装它们。


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的--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/issues/5243
Phil Gyford
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.