Search code examples
pythonaws-lambdaaws-lambda-layers

Python Layer Image Failing: "Unable to import module 'lambda_function': cannot import name '_imaging' from 'PIL'"


I'm simply trying to be able to use PIL in my Python 3.8 Lambda.

I'm trying the following steps:

  1. Based on this repo: https://github.com/hidekuma/lambda-layers-for-python-runtime
cd /mydir 
git clone https://github.com/hidekuma/lambda-layers-for-python-runtime.git 
cd lambda-layers-for-python-runtime 
mkdir dist 
docker-compose up --build
  1. Based on this guidance: https://www.splunk.com/en_us/blog/cloud/sharing-code-dependencies-with-aws-lambda-layers.html
aws lambda publish-layer-version --layer-name ImageStorageDependencies
    --description "A Python 3.8 runtime with PIL and boto3 installed." --license-info "MIT" --zip-file fileb://output.zip --compatible-runtimes python3.7 python3.8 --region us-east-2

I then choose my layer in the Lamda configuration, but when I run this code:

import json
import boto3
import io
from PIL import Image


def lambda_handler(event, context): 
    #etc

...I get the error:

[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': cannot import name '_imaging' from 'PIL' 

Where exactly am I going wrong?!?


Solution

  • Just to clarify, regarding your comment above, Pillow is just a repackaged, updated version of PIL because the original maintainers of PIL stopped working on it a long time ago. When you pip install Pillow, you still import it as PIL. In this case they are the same thing.

    To answer your question, the the Pillow install directions mention:

    Pillow >= 2.1.0 no longer supports import _imaging. Please use from PIL.Image import core as _imaging instead.

    I'm not sure where your code imports _imaging, so I think you have a few options:

    1. Use an older version of Pillow (pre 2.1.0)
    2. Find where you are importing _imaging and replace it with the updated from PIL.Image import core as _imaging
    3. Update to the current version of Pillow (see my update below)

    There is a fourth option which is redirecting the import manually, inspired by this question. I would only do this if you can't do one of the first three. Put this somewhere in your code that gets run before you do the import that is breaking things. You may have to tweak this slightly to make it work:

    from PIL.Image import core as _imaging
    import sys
    sys.modules['PIL._imaging'] = _imaging
    

    A later from PIL import _imaging should now really import the new core.

    Update:

    Updating Pillow may also solve the problem. In 7.2.0, I can import _imaging in the old way:

    >>> import PIL
    >>> from PIL import _imaging
    >>> print(PIL.__version__)
    7.2.0
    >>> print(_imaging)
    <module 'PIL._imaging' from '...\\lib\\site-packages\\PIL\\_imaging.cp37-win_amd64.pyd'>