Принудительный импорт зависимостей из отдельного места (AWS Lambda)
Я работаю с функцией AWS Lambda и имею несколько зависимостей.
В качестве примера для упрощения я буду использовать запросы (и да, я знаю, что запросы доступны из Botocore, но у меня есть другие зависимости, которых нет). структура моего проекта следующая:
lambda_function/
lambda_function.py
misc/
__init__.py
example.py
packages/
requests/
urllib3/
...
Каталог packages/ был получен путем выполненияpip install requests --target ./packages
в lambda_function.py у нас есть
from misc.example import foo
В example.py у нас есть
from packages import requests
def foo():
return requests.get('example.com')
который дает ModuleNotFoundError: нет модуля с именем 'urllib3', хотя urllib3 определенно находится внутри пакетов / я знаю, что этого можно избежать, просто поместив все в один каталог верхнего уровня, но существует довольно много зависимостей, и я хочу, чтобы все было в чистоте. Есть ли способ заставить запросы на импорт из каталога packages/ вместо этого или как-то добавить пакеты / в путь? Я уже пробовал делать
sys.path.append(os.path.abspath('lambda_function/packages'))
но безрезультатно.
1 ответ
Мои предлагаемые решения будут такими:
Просто скопируйте пакеты внутрь вашего лямбда-приложения, например:
- rm -rf ./lambda - mkdir -p ./lambda - pip install --upgrade pip - pip install --no-cache-dir -r requirement.txt -t lambda - cp -rf <application_code> lambda/
По сути, ваш код будет структурирован следующим образом:
lambda_function/ lambda_function.py misc/ __init__.py example.py requests/ urllib3/ ...
Не элегантный и может нанести вред.
Следующее решение:
sys.path.append(os.path.abspath('lambda_function/packages'))
У меня не было шансов работать, потому что, если вы просто запустите python и напечатаете sys.path, вы увидите кучу путей, а затем вы добавили свой в конце. Когда вы импортируете пакет, python сканирует путь от первого до последнего, и будет использоваться первый совпадающий (примерно так работают виртуальные среды). В вашем случае имя соответствовало тому, что лямбда имеет в качестве stdlib, решение в обычном мире было бы следующим:
sys.path.insert(0, os.path.abspath('lambda_function/packages'))
Будет ли это работать с лямбдой? Я предполагаю, что это было бы так, но это должно быть сделано в первую очередь до выполнения импорта, что само по себе иногда сложно.
Измените либо PATH, либо PYTHONPATH вашей лямбда-среды выполнения.
Фрагмент для терраформирования:
environment { variables = { ENV = "${terraform.workspace}" PYTHONPATH = "packages", } }
В моей среде задача находится в /var/task, а приведенная выше строка добавит /var/task/packages в sys.path.