Принудительный импорт зависимостей из отдельного места (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 ответ

Мои предлагаемые решения будут такими:

  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/
        ...
    

    Не элегантный и может нанести вред.

  2. Следующее решение:

            sys.path.append(os.path.abspath('lambda_function/packages'))
    

    У меня не было шансов работать, потому что, если вы просто запустите python и напечатаете sys.path, вы увидите кучу путей, а затем вы добавили свой в конце. Когда вы импортируете пакет, python сканирует путь от первого до последнего, и будет использоваться первый совпадающий (примерно так работают виртуальные среды). В вашем случае имя соответствовало тому, что лямбда имеет в качестве stdlib, решение в обычном мире было бы следующим:

            sys.path.insert(0, os.path.abspath('lambda_function/packages'))
    

    Будет ли это работать с лямбдой? Я предполагаю, что это было бы так, но это должно быть сделано в первую очередь до выполнения импорта, что само по себе иногда сложно.

  3. Измените либо PATH, либо PYTHONPATH вашей лямбда-среды выполнения.

    Фрагмент для терраформирования:

            environment {
      variables = {
        ENV            = "${terraform.workspace}"
        PYTHONPATH     = "packages",
      }
    }
    

    В моей среде задача находится в /var/task, а приведенная выше строка добавит /var/task/packages в sys.path.

Другие вопросы по тегам