How do I add python libraries to an AWS lambda function for Alexa?
Asked Answered
Y

10

82

I was following the tutorial to create an Alexa app using Python:

Python Alexa Tutorial

I was able to successfully follow all the steps and get the app to work.I now want to modify the python code and use external libraries such as import requests or any other libraries that I install using pip. How would I setup my lambda function to include any pip packages that I install locally on my machine?

Yellowthroat answered 10/8, 2016 at 15:1 Comment(0)
B
30

As it is described in the Amazon official documentation link here It is as simple as just creating a zip of all the folder contents after installing the required packages in your folder where you have your python lambda code.

As Vineeth pointed above in his comment, The very first step in moving from an inline code editor to a zip file upload approach is to change your lambda function handler name under configuration settings to include the python script file name that holds the lambda handler.

lambda_handler => {your-python-script-file-name}.lambda_handler.

CONFIGURE LAMBDA FUNCTION

Other solutions like python-lambda and lambda-uploader help with simplifying the process of uploading and the most importantly LOCAL TESTING. These will save a lot of time in development.

Burgh answered 6/8, 2017 at 9:6 Comment(4)
This way is not working for python 3.6 script with psycopg2. Getting error "Unable to import module 'ProcessRawRetailSalesUsingCOPY': No module named 'psycopg2._psycopg'" i am using windows7 prof with pycharm. Need some help on this if you can.Subassembly
Can we do that and still be able to modify the code inline? It seems that after adding a number of libraries, the zip file is large and it doesn't allow me to update the code inline anymore (th code itself is not large). Any workaround for this?Prefatory
@Prefatory package all your libraries in to a lambda layer and just keep your source code in your lambda zip and layer dependency to your lambda. This will reduce the size and you should be able to edit your code in line. Also checkout aws sam templates here => docs.aws.amazon.com/serverless-application-model/latest/…Burgh
Can you take a look here? I am already doing what you suggested i guess #72296467Bader
C
28

The official documentation is pretty good. In a nutshell, you need to create a zip file of a directory containing both the code of your lambda function and all external libraries you use at the top level.

You can simulate that by deactivating your virtualenv, copying all your required libraries into the working directory (which is always in sys.path if you invoke a script on the command line), and checking whether your script still works.

Castano answered 10/8, 2016 at 15:9 Comment(7)
I tried following the documentation. I pip installed the requests into the library. I took the color_game.py and added import requests at the top, requests directory, and requests-2.11.0.dist-info directory and sent those three to a zip file. I uploaded the zip file to lambda but when I try to run the Alexa function; it does not work. I get The remote endpoint could not be called, or the response it returned was invalid.Yellowthroat
I figured it out! I realized I wasn't changing the name of my handler. It should be the filename.lambda_handler if you go from inline code to a zip file. Thanks!Yellowthroat
We just started a project bstpy to expose a Python lambda as an http service. You may find it useful for testing. You can throw json payloads at it with curl or postman. If you try it with other Bespoken Tools you can a have very nice development environment.Defalcate
not blaming the messenger but this is a kluge on AWS's part. There should really be a more structured way to from pip/conda requirements to lambda deployment.Solution
The official documentation is pretty good. Gonna have to disagree with you there. The title and the first sentence of the page you linked to alone are entirely unclear to me as to whether they even have anything to do with importing packages to my AWS instance. (Is it about packaging something I've created? Who knows!)Donall
We started juniper as a way to automates the creation of python based artifacts as described in the official documentation. Building the zip manually is not a scalable solution, juniper was born out of our frustration building these artifacts with custom shell scripts.Urga
Can you take a look here? I am already doing what you suggested i guess #72296467Bader
B
8

You may want to look into using frameworks such as zappa which will handle packaging up and deploying the lambda function for you.

You can use that in conjunction with flask-ask to have an easier time making Alexa skills. There's even a video tutorial of this (from the zappa readme) here

Bulrush answered 29/12, 2016 at 1:10 Comment(0)
U
8

To solve this particular problem we're using a library called juniper. In a nutshell, all you need to do is create a very simple manifest file that looks like:

functions:
  # Name the zip file you want juni to create
  router:
    # Where are your dependencies located?
    requirements: ./src/requirements.txt.
    # Your source code.
    include:
    - ./src/lambda_function.py

From this manifest file, calling juni build will create the zip file artifact for you. The file will include all the dependencies you specify in the requirements.txt.

The command will create this file ./dist/router.zip. We're using that file in conjunction with a sam template. However, you can then use that zip and upload it to the console, or through the awscli.

Urga answered 2/4, 2019 at 19:32 Comment(1)
Last commit is from 2019.Hypodermic
D
4

Echoing @d3ming's answer, a framework is a good way to go at this point. Creating the deployment package manually isn't impossible, but you'll need to be uploading your packages' compiled code, and if you're compiling that code on a non-linux system, the chance of running into issues with differences between your system and the Lambda function's deployed environment are high.

You can then work around that by compiling your code on a linux machine or Docker container.. but between all that complexity you can get much more from adopting a framework.

Serverless is well adopted and has support for custom python packages. It even integrates with Docker to compile your python dependencies and build the deployment package for you.

If you're looking for a full tutorial on this, I wrote one for Python Lambda functions here.

Displume answered 28/2, 2018 at 16:24 Comment(0)
R
4

Amazon created a repository that deals with your situation: https://github.com/awsdocs/aws-lambda-developer-guide/tree/master/sample-apps/blank-python

The blank app is an example on how to push a lambda function that depends on requirements, with the bonus that being made by Amazon.

Everything you need to do is to follow the step by step, and update the repository based on your needs.

Rutter answered 21/5, 2020 at 15:28 Comment(0)
R
2

For some lambda POCs and fast lambda prototyping you can include and use the following function _install_packages, you can place a call to it before lambda handling function (for lambda init time package installation, if your deps need less than 10 seconds to install) or place the call at the beginning of the lambda handler (this will call the function exactly once at the first lambda event). Given pip install options included, packages to be installed must provide binary installable versions for manylinux.

_installed = False
def _install_packages(*packages):
    global _installed
    if not _installed:
        import os
        import sys
        import time
        _started = time.time()
        os.system("mkdir -p /tmp/packages")
        _packages = " ".join(f"'{p}'" for p in packages)
        print("INSTALLED:")
        os.system(
            f"{sys.executable} -m pip freeze --no-cache-dir")
        print("INSTALLING:")
        os.system(
            f"{sys.executable} -m pip install "
            f"--no-cache-dir --target /tmp/packages "
            f"--only-binary :all: --no-color "
            f"--no-warn-script-location {_packages}")
        sys.path.insert(0, "/tmp/packages")
        _installed = True
        _ended = time.time()
        print(f"package installation took: {_ended - _started:.2f} sec")

  # usage example before lambda handler
  _install_packages("pymssql", "requests", "pillow")
  def lambda_handler(event, context):
        pass # lambda code

  # usage example from within the lambda handler
  def lambda_handler(event, context):
        _install_packages("pymssql", "requests", "pillow")
        pass # lambda code

Given examples install python packages: pymssql, requests and pillow.

An example lambda that installs requests and then calls ifconfig.me to obtain it's egress IP address.

import json

_installed = False


def _install_packages(*packages):
    global _installed
    if not _installed:
        import os
        import sys
        import time
        _started = time.time()
        os.system("mkdir -p /tmp/packages")
        _packages = " ".join(f"'{p}'" for p in packages)
        print("INSTALLED:")
        os.system(
            f"{sys.executable} -m pip freeze --no-cache-dir")
        print("INSTALLING:")
        os.system(
            f"{sys.executable} -m pip install "
            f"--no-cache-dir --target /tmp/packages "
            f"--only-binary :all: --no-color "
            f"--no-warn-script-location {_packages}")
        sys.path.insert(0, "/tmp/packages")
        _installed = True
        _ended = time.time()
        print(f"package installation took: {_ended - _started:.2f} sec")

    # usage example before lambda handler


_install_packages("requests")


def lambda_handler(event, context):
    import requests
    return {
        'statusCode': 200,
        'body': json.dumps(requests.get('http://ifconfig.me').content.decode())
    }

Given single quote escaping is considered when building pip's command line, you can specify a version in a package spec like this pillow<9, the former will install most recent 8.X.X version of pillow.

Revelatory answered 13/9, 2022 at 3:0 Comment(0)
C
1

I too struggled for a while with this. The after deep diving into aws resources I got to know the lambda function on aws runs locally on a a linux. And it's very important to have the the python package version which matches with the linux version.

You may find more information on this on : https://aws.amazon.com/lambda/faqs/

Follow the steps to download the version. 1. Find the .whl image of the package from pypi and download it on you local. 2. Zip the packages and add them as layers in aws lambda 3. Add the layer to the lambda function.

Note: Please make sure that version you're trying to install python package matches the linux os on which the aws lambda performs computes tasks.

References : https://pypi.org/project/Pandas3/#files

Cussed answered 1/3, 2020 at 8:39 Comment(0)
S
1

A lot of python libraries can be imported via Layers here: https://github.com/keithrozario/Klayers, or your can use a framework like serverless that has plugins to package packages directly into your artifact.

Salangia answered 2/3, 2020 at 1:43 Comment(0)
S
0

The issue with layers is that it has to be exactly as written, and it is so easy to make tiny mistakes. Here are the steps:

  1. Create the zip file locally on your mac (you may change mylayer to something significant, but don't change python, use this exact structure. You can use pip freeze to list all installed packages and find the exact requirement name.)

    mkdir mylayer
    cd mylayer
    mkdir python
    pip install <requirement> -t python/
    zip -r mylayer.zip python
    
  2. Upload the layer to aws. Go to enter link description here

    This part is tricky - note that 'layer' is a resources shared by all lambdas of that specific region. So - define a new layer on the left panel (not under the specific lambda instance), and also make sure it's in the same region (oregon in this exampe).

    • Click "Create layer" (orange), name it, upload the zip file, and choose compatible architecture (I used both x86_64 and arm64).

    • Copy the Version ARN.

  3. Add the layer to your lambda: Go back to your lambda, at the bottom of the page click on "Add a layer" to add the layer you have created to that specific lambda. Then Choose 'Specify an ARN' and put the relevant ARN. Click Add, and it should work now: you'd see it in Layers, and your code should recognize the package.

Snuffer answered 29/5 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.