列出Python中的依赖项

时间:2017-02-14 22:01:30

标签: python

列出在其他地方部署工作项目所需的所有依赖项(比如在不同的操作系统上),最有效的方法是什么?

Python 2.7,Windows开发环境,不是每个项目使用virtualenv,而是全局开发环境,根据需要安装库,愉快地从一个项目跳到另一个项目。

我已经跟踪了我必须为给定项目安装的大多数(不确定所有)库。我跟踪自动安装它们的任何子依赖项。执行pip freeze会列出所有已安装的库以及所有其他库。

有没有办法列出您需要安装的内容,不多也不少,以便部署项目?

注意:无法想象这里已经没有Q + A,但我无法找到它。

编辑鉴于以下答案,请进行一些澄清。我的项目由一堆模块(我写的)组成,每个模块都有一堆import个。我应该只是将所有模块中的所有导入复制粘贴到一个文件中,排序消除重复,并从标准库中丢弃所有(以及我怎么知道它们)?或者,还有更好的方法?这就是问题所在。

8 个答案:

答案 0 :(得分:37)

pipreqs解决了这个问题。它会生成 项目级 requirement.txt文件。

安装pipreqs:pip install pipreqs

  1. 生成项目级requirements.txt文件:pipreqs /path/to/your/project/
  2. 需求文件将保存在/path/to/your/project/requirements.txt
  3. 如果您希望了解pipreqs超过pip freeze的更多优势,请阅读from here

答案 1 :(得分:11)

扫描您的2.4.0 :007 > str = "A more" => "A more" 2.4.0 :009 > str.split(/^([ab])[[:space:]]+/i) => ["", "A", "more"] 声明。您可能只导入您明确要导入的内容,而不是依赖项。

制作一个像import那样的列表,然后创建并激活virtualenv。

执行pip freeze,并尝试在该virtualenv中运行您的代码。注意任何pip install -r your_list例外情况,将它们与包匹配,然后添加到列表中。重复直到您的代码运行没有问题。

现在,您有一个列表可以提供给部署站点上的ImportError

这是非常手动的,但不需要外部工具,并强制您确保代码运行。 (运行测试套件作为检查很好,但还不够。)

答案 2 :(得分:1)

执行此操作的方法是分析您的导入。要自动执行此操作,请查看Snakefood。然后,您可以制作git push -f 文件并开始使用requirements.txt

以下将列出依赖项,不包括标准库中的模块:

virtualenv

相关问题:

Get a list of python packages used by a Django Project

list python package dependencies without loading them?

答案 3 :(得分:1)

我发现这里的答案对我来说效果不佳,因为我只想要从我们的存储库内部导入(例如,import requests 我不需要,但 from my.module.x import y 我确实需要) .

我注意到 PyInstaller 对此具有非常好的功能。我做了一些挖掘并设法找到了他们的依赖图代码,然后只是创建了一个函数来通过一些反复试验来做我想做的事情。我做了一个 gist here,因为我将来可能会再次需要它,但代码如下:

import os

from PyInstaller.depend.analysis import initialize_modgraph


def get_import_dependencies(*scripts):
    """Get a list of all imports required.
    Args: script filenames.
    Returns: list of imports
    """
    script_nodes = []
    scripts = set(map(os.path.abspath, scripts))

    # Process the scripts and build the map of imports
    graph = initialize_modgraph()
    for script in scripts:
        graph.run_script(script)
    for node in graph.nodes():
        if node.filename in scripts:
            script_nodes.append(node)

    # Search the imports to find what is in use
    dependency_nodes = set()
    def search_dependencies(node):
        for reference in graph.getReferences(node):
            if reference not in dependency_nodes:
                dependency_nodes.add(reference)
                search_dependencies(reference)
    for script_node in script_nodes:
        search_dependencies(script_node)

    return list(sorted(dependency_nodes))


if __name__ == '__main__':
    # Show the PyInstaller imports used in this file
    for node in get_import_dependencies(__file__):
        if node.identifier.split('.')[0] == 'PyInstaller':
            print(node)

所有节点类型都在PyInstaller.lib.modulegraph.modulegraph中定义,例如SourceModuleMissingModulePackageBuiltinModule。这些在执行检查时会很有用。

每一个都有一个 identifier (path.to.my.module),并且根据节点类型,它可能有一个 filename (C:/path/to/my/module/__init__.py) 和 {{1} } (packagepath)。

我真的不能发布任何额外的代码,因为它非常特定于我们将 ['C:/path/to/my/module']pyarmor 一起使用的设置,但我可以很高兴地说,到目前为止它可以完美运行。

答案 4 :(得分:0)

在您的终端上

pip安装pipdeptree

cd您的

pipdeptree

答案 5 :(得分:0)

我只会运行以下内容:

import importlib
import os
import pathlib
import re
import sys, chardet
from sty import fg

sys.setrecursionlimit(100000000)

dependenciesPaths = list()
dependenciesNames = list()
paths = sys.path
red = fg(255, 0, 0)
green = fg(0, 200, 0)
end = fg.rs


def main(path):
    try:
        print("Finding imports in '" + path + "':")

        file = open(path)
        contents = file.read()
        wordArray = re.split(" |\n", contents)

        currentList = list()
        nextPaths = list()
        skipWord = -1

        for wordNumb in range(len(wordArray)):
            word = wordArray[wordNumb]

            if wordNumb == skipWord:
                continue

            elif word == "from":
                currentList.append(wordArray[wordNumb + 1])
                skipWord = wordNumb + 2

            elif word == "import":
                currentList.append(wordArray[wordNumb + 1])

        currentList = set(currentList)
        for i in currentList:
            print(i)

        print("Found imports in '" + path + "'")
        print("Finding paths for imports in '" + path + "':")

        currentList2 = currentList.copy()
        currentList = list()

        for i in currentList2:
            if i in dependenciesNames:
                print(i, "already found")

            else:
                dependenciesNames.append(i)

                try:
                    fileInfo = importlib.machinery.PathFinder().find_spec(i)
                    print(fileInfo.origin)

                    dependenciesPaths.append(fileInfo.origin)

                    currentList.append(fileInfo.origin)

                except AttributeError as e:
                    print(e)
                    print(i)
                    print(importlib.machinery.PathFinder().find_spec(i))
                    # print(red, "Odd noneType import called ", i, " in path ", path, end, sep='')


        print("Found paths for imports in '" + path + "'")


        for fileInfo in currentList:
            main(fileInfo)

    except Exception as e:
        print(e)


if __name__ == "__main__":
    # args
    args = sys.argv
    print(args)

    if len(args) == 2:
        p = args[1]

    elif len(args) == 3:
        p = args[1]

        open(args[2], "a").close()
        sys.stdout = open(args[2], "w")

    else:
        print('Usage')
        print('PyDependencies <InputFile>')
        print('PyDependencies <InputFile> <OutputFile')

        sys.exit(2)

    if not os.path.exists(p):
        print(red, "Path '" + p + "' is not a real path", end, sep='')

    elif os.path.isdir(p):
        print(red, "Path '" + p + "' is a directory, not a file", end, sep='')

    elif "".join(pathlib.Path(p).suffixes) != ".py":
        print(red, "Path '" + p + "' is not a python file", end, sep='')

    else:
        print(green, "Path '" + p + "' is a valid python file", end, sep='')

        main(p)

    deps = set(dependenciesNames)

    print(deps)

    sys.exit()

答案 6 :(得分:0)

这个答案是为了帮助某人列出 Python 脚本本身的版本的所有依赖项。这将列出用户虚拟环境中的所有依赖项。

from pip._internal.operations import freeze

x = freeze.freeze()
for dependency in x:
   print(dependency)

为此,您需要安装 pip 作为依赖项。使用以下命令安装pip依赖。

pip install pip

打印输出如下所示。

certifi==2020.12.5
chardet==4.0.0
idna==2.10
numpy==1.20.3
oauthlib==3.1.0
pandas==1.2.4
pip==21.1.2
python-dateutil==2.8.1
pytz==2021.1
requests==2.25.1
requests-oauthlib==1.3.0
setuptools==41.2.0
six==1.16.0
urllib3==1.26.4

答案 7 :(得分:0)

您可以简单地使用 pipreqs,安装它:

pip install pipreqs

然后,在文件目录中键入:pipreqs .。 将为您创建一个名为 requirements 的文本文件,如下所示:

numpy==1.21.1
pytest==6.2.4
matplotlib==3.4.2
PySide2==5.15.2