3

I am using Lambda-uploader to write python lambda code and move the zip to AWS. I created a included my jar files and the zip folders structure like below.

enter image description here

The code I'm using is from AWS portal and is using PIL class. I included the Pillow library in Lambda-uploader as a requirement but when I create my Lambda function on Lambda console by importing the created zip file I get the following error message. Any help is appreciated.

Error:

START RequestId: e4893543-93aa-11e7-b4b9-89453f1042aa Version: $LATEST
Unable to import module 'CreateThumbnail': cannot import name _imaging

END RequestId: e4893543-93aa-11e7-b4b9-89453f1042aa
REPORT RequestId: e4893543-93aa-11e7-b4b9-89453f1042aa  Duration: 0.44 ms   Billed Duration: 100 ms     Memory Size: 512 MB Max Memory Used: 33 MB

lambda.josn

{
  "name": "CreateThumbnail",
  "description": "It does things",
  "region": "us-east-1",
  "runtime": "python2.7",
  "handler": "CreateThumbnail.lambda_handler",
  "role": "arn:aws:iam::0000000000:role/LambdaTest",
  "requirements": ["Pillow"],
  "ignore": [
    "circle\\.yml$",
    "\\.git$",
    "/.*\\.pyc$"
  ],
  "timeout": 30,
  "memory": 512
}

python code:

from __future__ import print_function
import boto3
import os
import sys
import uuid
from PIL import Image
import PIL.Image

s3_client = boto3.client('s3')

def resize_image(image_path, resized_path):
    with Image.open(image_path) as image:
        image.thumbnail(tuple(x / 2 for x in image.size))
        image.save(resized_path)

def handler(event, context):
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = record['s3']['object']['key'] 
        download_path = '/tmp/{}{}'.format(uuid.uuid4(), key)
        upload_path = '/tmp/resized-{}'.format(key)

        s3_client.download_file(bucket, key, download_path)
        resize_image(download_path, upload_path)
        s3_client.upload_file(upload_path, '{}resized'.format(bucket), key)
gabi
  • 1,324
  • 4
  • 22
  • 47
  • Check : http://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html I am not aware of python much but in java if I need external libraries then we need to create fat jar/zip file which includes all external libraries. – Suyash Sep 07 '17 at 11:15
  • Thanks. I did the same here. I included the zip file structure in my question. – gabi Sep 07 '17 at 12:00
  • I have found similar question on below link : https://stackoverflow.com/questions/25340698/importerror-cannot-import-name-imaging – Suyash Sep 08 '17 at 04:23

3 Answers3

10

I had the exact same problem and I solved it. The tl;dr version at the end.
The _imaging is a dynamically linked shared object library (with a .so extension). This is roughly the Linux equivalent of Windows DLL modules. You can take a look at this module inside the PIL folder.
The problem is that these .so files are compiled files that target the local machine's architecture. So if you do pip install Pillow on Windows, the dynamically linked library cannot be used on any other OS or architecture.
AWS lambda uses Amazon Linux execution environment. Not Ubuntu, Amazon Linux. So if you want to use dynamically linked shared object library on lambda, your best bet is to install all the libraries in a similar environment. Thankfully, EC2 offers the exact same execution environment as that of lambda. So, I spun off a temporary EC2 instance. Remote logged into it via SSH/Putty and installed all the dependencies. Then I zipped it along with my own code and published it to lambda. My program works fine now!

TL;DR

  • Spin off an EC2 instance with Amazon Linux execution environment.
  • Install dependencies like Pillow by remote logging via SSH/Putty.
  • Zip your own code along with libraries and publish on Lambda.

Half way through the process, I came across a nice blog by Matthew Perry explaining this entire process.

PodGen4
  • 338
  • 4
  • 12
2

You can also use a precompiled version of the PIL from:

https://github.com/Miserlou/lambda-packages

Just extract PIL folder to the deployment package and it should work.

It is not the most elegant solution but it will save you time bothering with compiling on EC2 instance.

ljmocic
  • 1,677
  • 2
  • 18
  • 23
  • 1
    This worked for me. Just downloaded the .tar.gz, extracted the content into my project (not the parent folder, I extracted all the .so files and the PIL folder into my project's root), and zipped it. It ran like a charm. – AFP_555 Apr 15 '18 at 06:11
0

This is just because of the version mismatch that our local machine has and AWS lambda has.

Check out the versions of python running on aws lambda and in your local machine .If the python versions are mismatching, then try to change the version in either AWS lambda or local machine...

Ex : python 3.9 in AWS lambda and python 3.9 in your local machine(as per the present version, you can opt for whatever version you prefer...But I would recommend for the latest version)

Both versions should match and then, try to upload the zip file of your project..Then absolutely you are good to go..

Thank you