Commit 5c954136 authored by Claude Paroz's avatar Claude Paroz
Browse files

Fixed #15644 -- Improved Django File wrapper to support more file-like...

Fixed #15644 -- Improved Django File wrapper to support more file-like objects. Thanks nickname123 and Michael Palumbo for working on the patch.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@17871 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 5e047ed8
Loading
Loading
Loading
Loading
+11 −6
Original line number Diff line number Diff line
@@ -36,8 +36,13 @@ class File(FileProxyMixin):
        if not hasattr(self, '_size'):
            if hasattr(self.file, 'size'):
                self._size = self.file.size
            elif os.path.exists(self.file.name):
            elif hasattr(self.file, 'name') and os.path.exists(self.file.name):
                self._size = os.path.getsize(self.file.name)
            elif hasattr(self.file, 'tell') and hasattr(self.file, 'seek'):
                pos = self.file.tell()
                self.file.seek(0, os.SEEK_END)
                self._size = self.file.tell()
                self.file.seek(pos)
            else:
                raise AttributeError("Unable to determine the file's size.")
        return self._size
@@ -61,12 +66,12 @@ class File(FileProxyMixin):

        if hasattr(self, 'seek'):
            self.seek(0)
        # Assume the pointer is at zero...
        counter = self.size

        while counter > 0:
            yield self.read(chunk_size)
            counter -= chunk_size
        while True:
            data = self.read(chunk_size)
            if not data:
                break
            yield data

    def multiple_chunks(self, chunk_size=None):
        """
+41 −2
Original line number Diff line number Diff line
# -*- coding: utf-8 -*-
from __future__ import absolute_import

import errno
import os
import shutil
@@ -17,12 +19,13 @@ except ImportError:

from django.conf import settings
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
from django.core.files.base import ContentFile
from django.core.files.base import File, ContentFile
from django.core.files.images import get_image_dimensions
from django.core.files.storage import FileSystemStorage, get_storage_class
from django.core.files.uploadedfile import UploadedFile
from django.test import SimpleTestCase
from django.utils import unittest
from ..servers.tests import LiveServerBase

# Try to import PIL in either of the two ways it can end up installed.
# Checking for the existence of Image is enough for CPython, but
@@ -544,6 +547,42 @@ class ContentFileTestCase(unittest.TestCase):
    def test_content_file_default_name(self):
        self.assertEqual(ContentFile("content").name, None)

    def test_content_file_custome_name(self):
    def test_content_file_custom_name(self):
        name = "I can have a name too!"
        self.assertEqual(ContentFile("content", name=name).name, name)

class NoNameFileTestCase(unittest.TestCase):
    """
    Other examples of unnamed files may be tempfile.SpooledTemporaryFile or
    urllib.urlopen()
    """
    def test_noname_file_default_name(self):
        self.assertEqual(File(StringIO('A file with no name')).name, None)

    def test_noname_file_get_size(self):
        self.assertEqual(File(StringIO('A file with no name')).size, 19)

class FileLikeObjectTestCase(LiveServerBase):
    """
    Test file-like objects (#15644).
    """
    def setUp(self):
        self.temp_dir = tempfile.mkdtemp()
        self.storage = FileSystemStorage(location=self.temp_dir)

    def tearDown(self):
        shutil.rmtree(self.temp_dir)

    def test_urllib2_urlopen(self):
        """
        Test the File storage API with a file like object coming from urllib2.urlopen()
        """

        file_like_object = self.urlopen('/example_view/')
        f = File(file_like_object)
        stored_filename = self.storage.save("remote_file.html", f)

        stored_file = self.storage.open(stored_filename)
        remote_file = self.urlopen('/example_view/')

        self.assertEqual(stored_file.read(), remote_file.read())