Зависимости списков в Python

Каков наиболее эффективный способ перечисления всех зависимостей, необходимых для развертывания рабочего проекта в другом месте (скажем, в другой ОС)?

Python 2.7, среда разработки Windows, не использующая virtualenv для каждого проекта, а глобальная среда разработки, устанавливающая библиотеки по мере необходимости, с радостью переходя от одного проекта к другому.

Я отслеживал большинство (не все) библиотек, которые мне пришлось установить для данного проекта. Я не отслеживал никаких зависимостей, которые были автоматически установлены вместе с ними. В pip freeze перечислены оба, а также все остальные библиотеки, которые когда-либо были установлены.

Есть ли способ перечислить, что вам нужно установить, не больше, не меньше, чтобы развернуть проект?

РЕДАКТИРОВАТЬ В связи с ответами ниже, некоторые разъяснения. Мой проект состоит из нескольких модулей (которые я написал), каждый из которых содержит группу import. Должен ли я просто скопировать и вставить все импортированные из всех модулей в один файл, отсортировать, исключив дубликаты, и выбросить все из стандартной библиотеки (и как я узнаю, что они есть)? Или есть лучший способ? Это вопрос.

Ответы

Ответ 1

Сканируйте свои операторы import. Скорее всего, вы импортируете только то, что явно хотите импортировать, а не зависимости.

Создайте список, подобный pip freeze, создайте и активируйте virtualenv.

Сделайте pip install -r your_list и попробуйте запустить свой код в этом pip install -r your_list. ImportError исключения ImportError, сопоставляйте их с пакетами и добавляйте в свой список. Повторяйте, пока ваш код не будет работать без проблем.

Теперь у вас есть список для подачи на pip install на вашем сайте развертывания.

Это крайне ручно, но не требует внешних инструментов и заставляет вас следить за тем, чтобы ваш код работал. (Запуск тестового набора в качестве чека велик, но не достаточен.)

Ответ 2

pipreqs решает проблему. Он генерирует файл require.txt уровня проекта.

Установить pipreqs: pip install pipreqs

  1. Создайте файл pipreqs/path/to/your/project/ уровне проекта: pipreqs/path/to/your/project/
  2. Файл требований будет сохранен в /path/to/your/project/requirements.txt

Если вы хотите узнать больше о преимуществах pipreqs сравнению с pip freeze, прочтите это здесь

Ответ 3

Способ сделать это - проанализировать ваш импорт. Чтобы автоматизировать это, проверьте Snakefood. Затем вы можете создать файл requirements.txt и получить доступ к использованию virtualenv.

Ниже перечислены зависимости, исключая модули из стандартной библиотеки:

sfood -fuq package.py | sfood-filter-stdlib | sfood-target-files 

Связанные вопросы:

Получить список пакетов python, используемых проектом Django

список зависимостей пакета python без их загрузки?

Ответ 4

На вашем терминале:

pip install pipdeptree

cd ваш

pipdeptree

Ответ 5

Я бы просто запустил что-то вроде этого:

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()