Search code examples
pythondjango-rest-frameworkpython-imaging-library

Pillow gives AttributeError: 'NoneType' object has no attribute 'seek' when trying to save a file


I'm trying to create a view in Django, using Django REST Framework and its FileUploadParser, where I can upload an image to, and it then stores both the original image and a thumbnail.

class ImageUploadParser(FileUploadParser):
    media_type = "image/*"


class ImageUploadView(APIView):
    permission_classes = (permissions.IsAuthenticated,)
    parser_classes = [ImageUploadParser]

    def post(self, request, filename):
        if "file" not in request.data:
            raise ParseError("Empty content")

        file_obj = request.data["file"]

        try:
            img = Image.open(file_obj)
            img.verify()
        except UnidentifiedImageError:
            raise ParseError("Unsupported image type")

        path = settings.MEDIA_ROOT / f"{request.user.id}"
        unique = uuid.uuid4().hex
        extension = img.format.lower()
        filename_full = f"{unique}.{extension}"
        filename_thumb = f"{unique}.thumb.{extension}"

        if not os.path.exists(path):
            os.makedirs(path)

        img.thumbnail((580, 580), Image.ANTIALIAS)
        img.save(path / filename_thumb, "image/png", optimize=True)

        return Response(f"{request.user.id}/{filename_full}", status=status.HTTP_201_CREATED)

When I post a file, this is the error I get:

Internal Server Error: /api/uploads/upload/test.png
Traceback (most recent call last):
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/PIL/ImageFile.py", line 182, in load
    seek = self.load_seek
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/PIL/Image.py", line 529, in __getattr__
    raise AttributeError(name)
AttributeError: load_seek

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/asgiref/sync.py", line 486, in thread_handler
    raise exc_info[1]
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 43, in inner
    response = await get_response(request)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 253, in _get_response_async
    response = await wrapped_callback(
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/asgiref/sync.py", line 448, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "/opt/homebrew/Cellar/[email protected]/3.10.9/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/tasks.py", line 408, in wait_for
    return await fut
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/asgiref/current_thread_executor.py", line 22, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/asgiref/sync.py", line 490, in thread_handler
    return func(*args, **kwargs)
  File "/opt/homebrew/Cellar/[email protected]/3.10.9/Frameworks/Python.framework/Versions/3.10/lib/python3.10/contextlib.py", line 79, in inner
    return func(*args, **kwds)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 55, in wrapped_view
    return view_func(*args, **kwargs)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/django/views/generic/base.py", line 103, in view
    return self.dispatch(request, *args, **kwargs)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/Users/kevin/Workspace/cn-django/criticalnotes/uploads/views.py", line 74, in post
    img.thumbnail((580, 580), Image.ANTIALIAS)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/PIL/Image.py", line 2618, in thumbnail
    im = self.resize(size, resample, box=box, reducing_gap=reducing_gap)
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/PIL/Image.py", line 2156, in resize
    self.load()
  File "/Users/kevin/Workspace/cn-django/.venv/lib/python3.10/site-packages/PIL/ImageFile.py", line 185, in load
    seek = self.fp.seek
AttributeError: 'NoneType' object has no attribute 'seek'

I am not sure what is going wrong, what is None, because img is not None at least.


Solution

  • This is because Pillow's verify() function closes the underlying file descriptor, after which functions like seek no longer exist internally.

    You will need to use PIL.Image.open() to open the Image again before calling save().

    For reference, see: