【问题标题】:How to find a Python package's dependencies如何查找 Python 包的依赖项
【发布时间】:2015-06-27 09:30:25
【问题描述】:

如何以编程方式获取 Python 包的依赖项列表?

标准的setup.py 已记录了这些内容,但我无法找到一种简单的方法来 Python 或命令行访问它。

理想情况下,我正在寻找类似的东西:

$ pip install somepackage --only-list-deps
kombu>=3.0.8
billiard>=3.3.0.13
boto>=2.26

或:

>>> import package_deps
>>> package = package_deps.find('somepackage')
>>> print package.dependencies
['kombu>=3.0.8', 'billiard>=3.3.0.13', 'boto>=2.26']

注意,我不是在谈论导入包和查找所有引用的模块。虽然这可能会找到大多数依赖包,但它无法找到所需的最低版本号。这仅存储在 setup.py 中。

【问题讨论】:

  • 这里有不少答案显示 pip 被导入以在程序中使用。 documentation for pip 强烈建议不要使用这种 pip。请记住,以防这些解决方案中的任何一个被用于任何重要的事情。

标签: python pip


【解决方案1】:

除了pip show [package name] 命令,还有pipdeptree

做吧

$ pip install pipdeptree

然后运行

$ pipdeptree

它会以树的形式显示你的依赖关系,例如,

flake8==2.5.0
  - mccabe [required: >=0.2.1,<0.4, installed: 0.3.1]
  - pep8 [required: !=1.6.0,>=1.5.7,!=1.6.1,!=1.6.2, installed: 1.5.7]
  - pyflakes [required: >=0.8.1,<1.1, installed: 1.0.0]
ipdb==0.8
  - ipython [required: >=0.10, installed: 1.1.0]

该项目位于https://github.com/naiquevin/pipdeptree,您还可以在其中找到使用信息。

【讨论】:

  • pipdeptree 显示所有 已安装包的依赖关系,而不仅仅是给定包的依赖关系。虽然您可以过滤其 --json 输出,但它仍然取决于已安装的软件包。
  • 是的,但是当您想了解为什么安装了不在您的 requirements.txt 中的软件包时,答案仍然很有用 :)
  • 另外,您可以使用-p option 仅选择您想要探索其依赖关系的几个包。
  • pipdeptree 在优化requirements.txt 时非常有用。 $ pipdeptree | grep -P '^\w+' 这仅输出顶级包。更多信息here
  • @DeepamGupta Just pipdeptree 也应该在虚拟环境中工作。
【解决方案2】:

尝试在pip中使用show命令,例如:

$ pip show tornado
---
Name: tornado
Version: 4.1
Location: *****
Requires: certifi, backports.ssl-match-hostname

更新(检索指定版本的部门):

from pip._vendor import pkg_resources


_package_name = 'somepackage'
_package = pkg_resources.working_set.by_key[_package_name]

print([str(r) for r in _package.requires()])  # retrieve deps from setup.py

Output: ['kombu>=3.0.8', 
         'billiard>=3.3.0.13', 
         'boto>=2.26']

【讨论】:

  • 告诉你的版本,而不是它的依赖项;他们刚刚被列出。
  • 是的,但它没有显示“所需的最低版本号”,因为 OP 要求:
  • 不知怎的,$ pip3 show beautifulsoup4 对我来说是空的 Requires: ——beautifulsoup4 不依赖于任何东西吗?
  • @xealits,我刚刚尝试在 virtualenv 中安装 beautifulsoup4,看起来它不依赖任何东西。
  • @PythonJin,是的,显然它只使用标准包。我对此有点惊讶。干得好,beautifulsoup4
【解决方案3】:

关于在 Windows 机器上找到和测试的方法的简要总结:

  1. 解析PyPI的json文件:https://pypi.org/pypi/&lt;package&gt;/&lt;version&gt;/json(#7)

  2. 勾选/site-packages/&lt;package-version&gt;.dist-info/METADATA#13,需要预安装)

  3. pip install --no-install &lt;package&gt;:已弃用 (#11)

  4. pip install --download &lt;package&gt;:已弃用 (#12)

  5. pip show &lt;package&gt;#1#2,需要预安装)

  6. 使用 import pippip._vendor.pkg_resources 编写脚本:已弃用 (#6)

  7. setuptools包的import pkg_resources编写脚本(#4,需要预安装)

  8. https://libraries.io/ (#5)

  9. 使用pipdeptree 包(#3#8,需要预安装)

  10. 使用Johnnydep 包(#10):很多情况下测试挂起。

  11. conda info [package_name]:已弃用 (#9)

  12. conda search [package_name] --info

  • 请注意,可以列出其他包:vc2015_runtimepython_abilibflang 等。
  • 请注意,此方法可以根据构建和渠道列出不同的包。
    例如conda search "Django==3.2" --info -c conda-forge
django 3.2 pyhd3eb1b0_0
-----------------------
file name   : django-3.2-pyhd3eb1b0_0.conda
...
timestamp   : 2021-04-06 20:19:41 UTC
dependencies:
  - asgiref
  - psycopg2
  - python
  - pytz
  - sqlparse

django 3.2 pyhd8ed1ab_0
-----------------------
file name   : django-3.2-pyhd8ed1ab_0.tar.bz2
...
timestamp   : 2021-04-07 21:15:25 UTC
dependencies:
  - asgiref >=3.3.2,<4
  - python >=3.6
  - pytz
  - sqlparse >=0.2.2

还有一点需要注意的是,每种方法都可以提供不同的结果。

例如,requests/setup.pyidentifieschardetidnaurllib3certifi 是必需的。此外,可能需要额外的包pyOpenSSLcryptographysocksPySockswin-inet-pton

  • 方法1和2都同意。
  • 方法 8 只是列出所有这些(按下探索依赖项按钮只是挂起)。
  • 方法12只列出chardetidnaurllib3certifi
  • 如果在 Linux docker 中使用 pip 安装 requests,则方法 5 和 7 不会列出任何依赖项。
  • 方法5、7、9、10列出chardetidnaurllib3certifi,如果requests安装在Windows机器的conda环境中。

【讨论】:

    【解决方案4】:

    这里有很多答案显示 pip 被导入以在程序中使用。 documentation for pip strongly advises against this usage of pip

    您实际上可以直接导入 pkg_resources 并使用相同的逻辑,而不是通过 pip 导入访问 pkg_resources(这实际上是 pip 文档中为希望查看包元信息的任何人链接的建议解决方案之一以编程方式)。

    import pkg_resources
    
    _package_name = 'yourpackagename'
      
    def get_dependencies_with_semver_string():
        package = pkg_resources.working_set.by_key[_package_name]
        return [str(r) for r in package.requires()]
    

    如果您在查找包名时遇到问题,pkg_resources.working_set 返回的WorkingSet 实例实现了__iter__,因此您可以打印所有这些并希望在那里找到您的:)

    p>

    import pkg_resources
    
    def print_all_in_working_set():
        ws = pkg_resources.working_set
        for package_metadata in ws:
            print(package_metadata)
    

    这适用于 python 2 和 3(尽管您需要调整 python2 的打印语句)。

    【讨论】:

      【解决方案5】:

      使用https://libraries.io/。这是一个在使用 pip 安装之前探索依赖关系的好地方。

      例如。输入 google-cloud-storage 并搜索,然后您可以找到该库的页面 (https://libraries.io/rubygems/google-cloud-storage)。从“Releases”(默认为最新)中选择您要探索依赖项的版本,在“Dependencies”下,您可以找到依赖项列表及其支持的版本。

      【讨论】:

      • 非常有用,谢谢。
      【解决方案6】:

      (这是一个遗留答案,对于现代 PIP 版本应避免使用,并留在这里以供旧 PIP 版本参考) 亚历克斯的回答很好(+1)。在python中:

      pip._vendor.pkg_resources.working_set.by_key['twisted'].requires()
      

      应该返回类似的东西

      [Requirement.parse('zope.interface>=3.6.0')]
      

      其中 twisted 是包的名称,您可以在字典中找到它:

      pip._vendor.pkg_resources.WorkingSet().entry_keys
      

      全部列出:

      dict = pip._vendor.pkg_resources.WorkingSet().entry_keys
      for key in dict:
          for name in dict[key]:
              req =pip._vendor.pkg_resources.working_set.by_key[name].requires()
              print('pkg {} from {} requires {}'.format(name,
                                                        key,
                                                        req))
      

      应该给你这样的列表:

      pkg pyobjc-framework-syncservices from /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC requires [Requirement.parse('pyobjc-core>=2.5.1'), Requirement.parse('pyobjc-framework-Cocoa>=2.5.1'), Requirement.parse('pyobjc-framework-CoreData>=2.5.1')]
      

      【讨论】:

      • 最近的版本有什么变化吗? _vendor 属性似乎在 pip 版本 19.1.1 中不存在(编辑:好吧,它似乎已移至最新 python 版本中的 pkg_resources 包!)
      • 是的,事情发生了变化,我将考虑更新或删除它以支持下面的建议。
      • 从我的角度来看,亚历克斯的回答只是部分好(pip show 部分很好,而不是其余部分)。要么使用pip showpipdeptree,要么直接使用setuptools'pkg_resources查看Jordan Mackie的回答。
      【解决方案7】:

      有一个不错的工具johnnydep。这样做的好处是不必安装要检查的包。

      pip install johnnydep
      

      像这样使用它:

      johnnydep deepspeech-tflite
      

      【讨论】:

        【解决方案8】:

        在python中根据这个article试试这个:

        import pip 
        installed_packages = pip.get_installed_distributions()
        installed_packages_list = sorted(["%s==%s" % (i.key, i.version)
             for i in installed_packages]) 
        print(installed_packages_list)
        

        它会显示如下:

        ['behave==1.2.4', 'enum34==1.0', 'flask==0.10.1', 'itsdangerous==0.24', 
         'jinja2==2.7.2', 'jsonschema==2.3.0', 'markupsafe==0.23', 'nose==1.3.3', 
         'parse-type==0.3.4', 'parse==1.6.4', 'prettytable==0.7.2', 'requests==2.3.0',
         'six==1.6.1', 'vioozer-metadata==0.1', 'vioozer-users-server==0.1', 
         'werkzeug==0.9.4']
        

        【讨论】:

          【解决方案9】:

          标准库从 3.8 及更高版本开始提供 importlib.metadata.requires()

          In [1]: from importlib.metadata import requires
          
          In [2]: requires('pytype')
          Out[2]:
          ['attrs (>=21.2.0)',
           'importlab (>=0.6.1)',
           'libcst',
           'ninja (>=1.10.0.post2)',
           'pyyaml (>=3.11)',
           'six',
           'tabulate',
           'toml',
           'typed-ast (>=1.4.3)',
           'dataclasses ; python_version < "3.7"']
          

          对于较旧的 Python 版本,可以使用 importlib-metadata。 Python 文档中的相关部分:Distribution requirements

          如果你需要解析requires()返回的字符串,我强烈建议使用packaging库,因为它的packaging.requirements模块是PEP 508的参考实现。具有复杂依赖规范字符串的示例:

          In [3]: from packaging.requirements import Requirement
          
          In [4]: spec = 'requests [security,test] (>=2.21.0) ; implementation_name == "cpython"'
          
          In [5]: r = Requirement(spec)
          
          In [6]: r.name
          Out[6]: 'requests'
          
          In [7]: r.specifier
          Out[7]: <SpecifierSet('>=2.21.0')>
          
          In [8]: r.extras
          Out[8]: {'security', 'test'}
          
          In [9]: r.marker
          Out[9]: <Marker('implementation_name == "cpython"')>
          

          【讨论】:

            猜你喜欢
            • 2013-03-23
            • 2017-01-07
            • 1970-01-01
            • 2018-02-23
            • 1970-01-01
            • 2016-05-24
            • 2011-11-17
            • 2011-02-12
            相关资源
            最近更新 更多