Ticket #8817: 8817-final.patch

File 8817-final.patch, 3.4 KB (added by Armin Ronacher, 16 years ago)

proper fix for 8817.

  • django/core/files/images.py

     
    2828    """Returns the (width, height) of an image, given an open file or a path."""
    2929    from PIL import ImageFile as PILImageFile
    3030    p = PILImageFile.Parser()
     31    close = False
    3132    if hasattr(file_or_path, 'read'):
    3233        file = file_or_path
    3334    else:
    3435        file = open(file_or_path, 'rb')
    35     while 1:
    36         data = file.read(1024)
    37         if not data:
    38             break
    39         p.feed(data)
    40         if p.image:
    41             return p.image.size
    42     return None
     36        close = True
     37    try:
     38        while 1:
     39            data = file.read(1024)
     40            if not data:
     41                break
     42            p.feed(data)
     43            if p.image:
     44                return p.image.size
     45        return None
     46    finally:
     47        if close:
     48            file.close()
  • tests/regressiontests/file_storage/tests.py

     
    9090import time
    9191import shutil
    9292import tempfile
     93from cStringIO import StringIO
    9394from unittest import TestCase
    9495from django.conf import settings
    9596from django.core.files.base import ContentFile
    9697from django.core.files.storage import FileSystemStorage
     98from django.core.files.images import get_image_dimensions
    9799try:
    98100    import threading
    99101except ImportError:
    100102    import dummy_threading as threading
    101103
     104try:
     105    # Checking for the existence of Image is enough for CPython, but
     106    # for PyPy, you need to check for the underlying modules
     107    from PIL import Image, _imaging
     108except ImportError:
     109    Image = None
     110
    102111class SlowFile(ContentFile):
    103112    def chunks(self):
    104113        time.sleep(1)
     
    141150        actual_mode = os.stat(self.storage.path(name))[0] & 0777
    142151        self.assertEqual(actual_mode, 0666)
    143152
     153if Image is not None:
     154
     155    # for ticket #8817
     156    class DimensionClosingBug(TestCase):
     157        def test_not_closing_of_files(self):
     158            empty_io = StringIO()
     159            try:
     160                get_image_dimensions(empty_io)
     161            finally:
     162                self.assert_(not empty_io.closed)
     163
     164        def test_closing_of_filenames(self):
     165            # provide a modified open() for the images module
     166            # that checks if the file was closed properly if the
     167            # function is called with a filename instead of an file
     168            # object.  get_image_dimensions will call our catching_open
     169            # instead of the regular builtin one.
     170
     171            _closed = []
     172            class FileWrapper(object):
     173                def __init__(self, f):
     174                    self.f = f
     175                def __getattr__(self, name):
     176                    return getattr(self.f, name)
     177                def close(self):
     178                    _closed.append(True)
     179                    self.f.close()
     180
     181            def catching_open(*args):
     182                return FileWrapper(open(*args))
     183
     184            from django.core.files import images
     185            images.open = catching_open
     186            try:
     187                get_image_dimensions(os.path.join(os.path.dirname(__file__), "test1.png"))
     188            finally:
     189                del images.open
     190            self.assert_(_closed)
Back to Top