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

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

当我冻结一个点子时,会看到大量未明确安装的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,并且在我不了解不意外卸载或升级它之前,不要依赖于软件包。

When I do a pip freeze I see large number of Python packages that I didn’t explicitly install, e.g.

$ 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.)

Is there a way for me to determine why pip installed these particular dependent packages? In other words, how do I determine the parent package that had these packages as dependencies?

For example, I might want to use Twisted and I don’t want to depend on a package until I know more about not accidentally uninstalling it or upgrading it.


回答 0

您可以尝试使用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]

You could try pipdeptree which displays dependencies as a tree structure e.g.:

$ 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

To get it run:

pip install pipdeptree


EDIT: as noted by @Esteban in the comments you can also list the tree in reverse with -r or for a single package with -p <package_name> so to find what installed Werkzeug you could run:

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

回答 1

pip show命令将显示指定软件包所需的软件包(请注意,必须已经安装了指定软件包):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show 是在pip版本1.4rc5中引入的

The pip show command will show what packages are required for the specified package (note that the specified package must already be installed):

$ pip show specloud

Package: specloud
Version: 0.4.4
Requires:
nose
figleaf
pinocchio

pip show was introduced in pip version 1.4rc5


回答 2

正如我最近在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

As I recently said on a hn thread, I’ll recommend the following:

Have a commented requirements.txt file with your main dependencies:

## this is needed for whatever reason
package1

Install your dependencies: pip install -r requirements.txt. Now you get the full list of your dependencies with 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

This allows you to keep your file structure with comments, nicely separating your dependencies from the dependencies of your dependencies. This way you’ll have a much nicer time the day you need to remove one of them :)

Note the following:

  • You can have a clean requirements.raw with version control to rebuild your full requirements.txt.
  • Beware of git urls being replaced by egg names in the process.
  • The dependencies of your dependencies are still alphabetically sorted so you don’t directly know which one was required by which package but at this point you don’t really need it.
  • Use pip install --no-install <package_name> to list specific requirements.
  • Use virtualenv if you don’t.

回答 3

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

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

You may also use a one line command which pipes the packages in requirements to pip show.

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

回答 4

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

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

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

First of all pip freeze displays all currently installed packages Python, not necessarily using PIP.

Secondly Python packages do contain the information about dependent packages as well as required versions. You can see the dependencies of particular pkg using the methods described here. When you’re upgrading a package the installer script like PIP will handle the upgrade of dependencies for you.

To solve updating of packages i recommend using PIP requirements files. You can define what packages and versions you need, and install them at once using pip install.


回答 5

使用pipupgrade

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

pipupgrade显示依赖关系图并突出显示每个程序包以进行可能的更新(基于语义版本控制)。它还以漂亮的方式显示冲突的子依赖关系。pipupgrade还确保升级存在于多个Python环境中的软件包。与Python2.7 +,Python3.4 +和pip9 +,pip10 +,pip18 +,pip19 +兼容。

Use pipupgrade!

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

pipupgrade displays a dependency graph and highlights each package for a possible update (based on semantic versioning). It also displays conflicting child dependencies in a pretty way. pipupgrade also ensures to upgrade packages present within multiple Python environments. Compatible with Python2.7+, Python3.4+ and pip9+, pip10+, pip18+, pip19+.


回答 6

(解决方法,不是真正的答案)

遇到同样的问题,因为没有安装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/

(workaround, not true answer)

Had the same problem, with lxml not installing and me wanting to know who needed lxml. Not who lxml needed. Ended up bypassing the issue by.

  1. noting where my site packages were being put.

  2. go there and recursive grep for the import (the last grep’s –invert-match serves to remove lxml’s own files from consideration).

Yes, not an answer as to how to use pip to do it, but I didn’t get any success out of the suggestions here, for whatever reason.

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

回答 7

我写了一个快速的脚本来解决这个问题。以下脚本将显示任何给定包的父(相关)包。这样,您可以确定升级或安装任何特定的软件包都是安全的。可以如下使用: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)))

I wrote a quick script to solve this problem. The following script will display the parent (dependant) package(s) for any given package. This way you can be sure it is safe to upgrade or install any particular package. It can be used as follows: 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)))