pythonamazon-web-servicesamazon-s3aws-lambdavideo-thumbnails

"module 'os' has no attribute 'add_dll_directory'" in aws lambda function


I'm facing an issue that os does not have an add_dll_directory attribute in the AWS lambda function on the trigger.

I have written code for creating a thumbnail of a video and I have tried it locally that's working fine but when I upload this function with the required libraries then I get this issue and still, I'm unable to resolve it. I did not get any help from the internet yet regarding this issue.

that is an issue that I'm facing

[ERROR] AttributeError: module 'os' has no attribute 'add_dll_directory'
Traceback (most recent call last):
  File "/var/lang/lib/python3.12/importlib/__init__.py", line 90, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1381, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1354, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1325, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 929, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 994, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/var/task/lambda_function.py", line 2, in <module>
    import cv2
  File "/var/task/cv2/__init__.py", line 11, in <module>
    import numpy
  File "/var/task/numpy/__init__.py", line 112, in <module>
    _delvewheel_patch_1_5_2()
  File "/var/task/numpy/__init__.py", line 109, in _delvewheel_patch_1_5_2
    os.add_dll_directory(libs_dir)

This is the code that I'm using for creating a thumbnail

import json
import cv2
import tempfile
from PIL import Image
from io import BytesIO
import boto3

s3 = boto3.client('s3')

def get_video_file(bucket, key):
    video_file = s3.get_object(Bucket=bucket, Key=key)['Body'].read()
    return video_file


def upload_image_file(image_byte_data, bucket, key):
    s3.put_object(Bucket=bucket, Key=key, Body=image_byte_data, ContentType="image/png")

def generate_thumbnail(video_byte_data):

    with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as temp_file:
        temp_file_path = temp_file.name
        temp_file.write(video_byte_data)


    video_capture = cv2.VideoCapture(temp_file_path, cv2.CAP_ANY)

    success, frame = video_capture.read()

    if success:
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        thumbnail_image = Image.fromarray(frame_rgb)

        thumbnail_size = (320,320)
        thumbnail_image.resize(thumbnail_size)

        thumbnail_data = BytesIO()

        thumbnail_image.save(thumbnail_data, format='PNG')

        thumbnail_bytes = thumbnail_data.getvalue()

        return thumbnail_bytes
    else:
        raise ValueError('Unable to read video frame')


def lambda_handler(event, context):
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']


    video_file = get_video_file(bucket, key)
    image_output_file = generate_thumbnail(video_file)
    upload_image_file(image_output_file, "thumbnail876", key.split(".")[0]+".png")
    
    return {
        "statusCode": 200,
        "body": json.dumps(
            {
                "message": "hello world",
            }
        ),
    }

Please can someone tell me why I'm facing this issue? and how can I resolve this? Thanks


Solution

  • Lambda runtime doesn't provide Pillow or openCV, and you seem to have packaged Windows binary distributions of your dependencies with your Lambda code.

    You need to package the distributions compatible with Amazon Linux and the architecture of your Lambda function (x86_64 or arm).

    The easiest way to do this is create a layer.

    1. Put the list of your dependencies (Pillow, opencv-python-headless, plus whatever else you need) into requirements.txt

    2. Run these commands:

      pip install \
        --platform manylinux2014_x86_64 \
        --target=python \
        --implementation cp \
        --python-version 3.12 \
        --only-binary=:all: \
        --upgrade \
        -r requirements.txt
      zip -r imaging.zip python/
      

      If your Lambda is running on ARM, replace manylinux2014_x86_64 with manylinux2014_aarch64

    3. Create the layer from the resulting zip file and use it in your lambda.