Зависимости списков в 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
- Создайте файл
pipreqs/path/to/your/project/
уровне проекта: pipreqs/path/to/your/project/
- Файл требований будет сохранен в /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()