Search code examples
pythonamazon-s3boto3python-imaging-libraryfalconframework

Upload Thumbnail Image to S3 using Boto3


I'm using the Falcon framework and Pillow to upload a profile picture of a contact to S3, then resizing that picture for a thumbnail, and then uploading that thumbnail.

I've looked at other answers but some of them require having bucket write access activated and some use django's default_storage feature which I don't have available.

client = boto3.client('s3',
    aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
    aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY')
)


class UploadResource(object):

    def on_post(self, req, res):
        #gathering file from SPA
        contact_id = req.get_param('id')
        filename = req.get_param('file').filename
        file = req.get_param('file').file
        salt = ''.join(chr(random.randint(97, 122)) for i in range(20))
        filename = salt + '-' + filename
        filename_thumb = salt + '-thumb-' + filename

        #uploading normal sized image
        client.upload_fileobj(file, 'contacts-cloud-images', filename)  

        #pull down image again and resize
        img = Image.open(requests.get(image_url, stream=True).raw)
        img.thumbnail((50,50))
        print(img.format, img.size)

        #save it to BytesIO container
        io = BytesIO()
        img.save(io, img.format)

        #upload value of BytesIO container
--->    client.upload_fileobj(io.getvalue(), 'contacts-cloud-images', filename_thumb)

I get the following error from the line with the arrow (---->):

ValueError: Fileobj must implement read


Solution

  • The error means client.upload_fileobj is expecting a file-like object that implements a read method, but you're passing it the content of the file-like object (io.getvalue()) instead of the file-like object itself (io)

    This is a link to the documentation of upload_fileobj

    Important non-related note: An important thing to note is you're naming the variable that holds your buffer io. io is also the name of a module of the standard library, and you're overwriting it. That should be an absolute no-no. Despite the local scope of your variable, I recommend you rename it to something meaninful, like file_content or image_content.