Browse Source

Fixed #11739 -- Made ContentFile support Unicode input

Claude Paroz 12 years ago
parent
commit
361d6738f8
3 changed files with 25 additions and 9 deletions
  1. 4 2
      django/core/files/base.py
  2. 8 4
      docs/ref/files/file.txt
  3. 13 3
      tests/regressiontests/file_storage/tests.py

+ 4 - 2
django/core/files/base.py

@@ -1,10 +1,11 @@
 from __future__ import unicode_literals
 
 import os
-from io import BytesIO, UnsupportedOperation
+from io import BytesIO, StringIO, UnsupportedOperation
 
 from django.utils.encoding import smart_text
 from django.core.files.utils import FileProxyMixin
+from django.utils import six
 from django.utils.encoding import python_2_unicode_compatible
 
 @python_2_unicode_compatible
@@ -132,7 +133,8 @@ class ContentFile(File):
     """
     def __init__(self, content, name=None):
         content = content or b''
-        super(ContentFile, self).__init__(BytesIO(content), name=name)
+        stream_class = StringIO if isinstance(content, six.text_type) else BytesIO
+        super(ContentFile, self).__init__(stream_class(content), name=name)
         self.size = len(content)
 
     def __str__(self):

+ 8 - 4
docs/ref/files/file.txt

@@ -91,14 +91,18 @@ The ``ContentFile`` Class
 .. class:: ContentFile(File)
 
     The ``ContentFile`` class inherits from :class:`~django.core.files.File`,
-    but unlike :class:`~django.core.files.File` it operates on string content,
-    rather than an actual file. For example::
+    but unlike :class:`~django.core.files.File` it operates on string content
+    (bytes also supported), rather than an actual file. For example::
 
         from __future__ import unicode_literals
         from django.core.files.base import ContentFile
 
-        f1 = ContentFile(b"my string content")
-        f2 = ContentFile("my unicode content encoded as UTF-8".encode('UTF-8'))
+        f1 = ContentFile("esta sentencia está en español")
+        f2 = ContentFile(b"these are bytes")
+
+    .. versionchanged:: 1.5
+
+        ContentFile also accepts Unicode strings.
 
 .. currentmodule:: django.core.files.images
 

+ 13 - 3
tests/regressiontests/file_storage/tests.py

@@ -21,6 +21,7 @@ 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 six
 from django.utils import unittest
 from ..servers.tests import LiveServerBase
 
@@ -538,16 +539,25 @@ class InconsistentGetImageDimensionsBug(unittest.TestCase):
         self.assertEqual(size_1, size_2)
 
 class ContentFileTestCase(unittest.TestCase):
-    """
-    Test that the constructor of ContentFile accepts 'name' (#16590).
-    """
+
     def test_content_file_default_name(self):
         self.assertEqual(ContentFile(b"content").name, None)
 
     def test_content_file_custom_name(self):
+        """
+        Test that the constructor of ContentFile accepts 'name' (#16590).
+        """
         name = "I can have a name too!"
         self.assertEqual(ContentFile(b"content", name=name).name, name)
 
+    def test_content_file_input_type(self):
+        """
+        Test that ContentFile can accept both bytes and unicode and that the
+        retrieved content is of the same type.
+        """
+        self.assertTrue(isinstance(ContentFile(b"content").read(), bytes))
+        self.assertTrue(isinstance(ContentFile("español").read(), six.text_type))
+
 class NoNameFileTestCase(unittest.TestCase):
     """
     Other examples of unnamed files may be tempfile.SpooledTemporaryFile or