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
This commit is contained in:
Claude Paroz 2012-04-05 15:44:04 +00:00
parent 5e047ed859
commit 5c954136ea
2 changed files with 52 additions and 8 deletions

View File

@ -36,8 +36,13 @@ class File(FileProxyMixin):
if not hasattr(self, '_size'): if not hasattr(self, '_size'):
if hasattr(self.file, 'size'): if hasattr(self.file, 'size'):
self._size = 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) 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: else:
raise AttributeError("Unable to determine the file's size.") raise AttributeError("Unable to determine the file's size.")
return self._size return self._size
@ -61,12 +66,12 @@ class File(FileProxyMixin):
if hasattr(self, 'seek'): if hasattr(self, 'seek'):
self.seek(0) self.seek(0)
# Assume the pointer is at zero...
counter = self.size
while counter > 0: while True:
yield self.read(chunk_size) data = self.read(chunk_size)
counter -= chunk_size if not data:
break
yield data
def multiple_chunks(self, chunk_size=None): def multiple_chunks(self, chunk_size=None):
""" """

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import absolute_import
import errno import errno
import os import os
import shutil import shutil
@ -17,12 +19,13 @@ except ImportError:
from django.conf import settings from django.conf import settings
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured 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.images import get_image_dimensions
from django.core.files.storage import FileSystemStorage, get_storage_class from django.core.files.storage import FileSystemStorage, get_storage_class
from django.core.files.uploadedfile import UploadedFile from django.core.files.uploadedfile import UploadedFile
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils import unittest 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. # 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 # 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): def test_content_file_default_name(self):
self.assertEqual(ContentFile("content").name, None) 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!" name = "I can have a name too!"
self.assertEqual(ContentFile("content", name=name).name, name) 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())