aws / aws-lambda-python-runtime-interface-client

Apache License 2.0
261 stars 74 forks source link

Runtime.ImportModuleError: Unable to import module '': No module named '' #26

Open nataliemona opened 3 years ago

nataliemona commented 3 years ago

Following Python 3.9 Alpine Linux instructions from: https://aws.amazon.com/blogs/aws/new-for-aws-lambda-container-image-support/

The only line I changed in the Dockerfile is: COPY app/* ${FUNCTION_DIR} to COPY app.py ${FUNCTION_DIR}

# Define global args
ARG FUNCTION_DIR="/home/app/"
ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.12"

# Stage 1 - bundle base image + runtime
# Grab a fresh copy of the image and install GCC
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS python-alpine
# Install GCC (Alpine uses musl but we compile and link dependencies with GCC)
RUN apk add --no-cache \
    libstdc++

# Stage 2 - build function and dependencies
FROM python-alpine AS build-image
# Install aws-lambda-cpp build dependencies
RUN apk add --no-cache \
    build-base \
    libtool \
    autoconf \
    automake \
    libexecinfo-dev \
    make \
    cmake \
    libcurl
# Include global args in this stage of the build
ARG FUNCTION_DIR
ARG RUNTIME_VERSION
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}
# Copy handler function
COPY app.py ${FUNCTION_DIR}
# Optional – Install the function's dependencies
# RUN python${RUNTIME_VERSION} -m pip install -r requirements.txt --target ${FUNCTION_DIR}
# Install Lambda Runtime Interface Client for Python
RUN python${RUNTIME_VERSION} -m pip install awslambdaric --target ${FUNCTION_DIR}

# Stage 3 - final runtime image
# Grab a fresh copy of the Python image
FROM python-alpine
# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}
# Copy in the built dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
# (Optional) Add Lambda Runtime Interface Emulator and use a script in the ENTRYPOINT for simpler local runs
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
COPY entry.sh /
RUN chmod 755 /usr/bin/aws-lambda-rie /entry.sh
ENTRYPOINT [ "/entry.sh" ]
CMD [ "app.handler" ]

app.py

import json

def handler(event, context):
    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "input": event,
    }
    response = {
        "statusCode": 200,
        "body": json.dumps(body),
    }
    return response

entry.sh

#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
    exec /usr/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $1
else
    exec /usr/local/bin/python -m awslambdaric $1
fi

Running: curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload": "hello world!"}' Getting the error: {"errorMessage": "Unable to import module '': No module named ''", "errorType": "Runtime.ImportModuleError"}

This is hard to debug because the module is an empty string.

I am able to connect to the docker container with docker exec -it <name> /bin/sh and then run the handler directly with python -c 'import app; print(app.handler({}, {}))'. The handler runs with no errors if I run it directly.

matthewchung74 commented 3 years ago

you might want to try something like this.

import json
import traceback

def respond(err, res=None):
    return {
        "statusCode": "400" if err else "200",
        "body": err["message"] if err else json.dumps(res),
        "headers": {"Content-Type": "application/json"},
    }

def lambda_handler(event, context): 
    try:
        import sys
        # from lib.inference import predict
    except Exception as e:
        error = str(e)
        stacktrace = json.dumps(traceback.format_exc())
        message = "Exception: " + error + "  Stacktrace: " + stacktrace
        err = {"message": message}
        return respond(err)

    return respond(None, "wow25520003")

i can't find the original link I got it from, but it will catch import errors.