소스 검색

Made FileSystemStorage accept both text and byte streams

Thanks Alexey Boriskin for his help on the patch.
Claude Paroz 12 년 전
부모
커밋
4e70ad11d2
2개의 변경된 파일20개의 추가작업 그리고 2개의 파일을 삭제
  1. 9 2
      django/core/files/storage.py
  2. 11 0
      tests/regressiontests/file_storage/tests.py

+ 9 - 2
django/core/files/storage.py

@@ -195,11 +195,18 @@ class FileSystemStorage(Storage):
                     fd = os.open(full_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, 'O_BINARY', 0))
                     try:
                         locks.lock(fd, locks.LOCK_EX)
+                        _file = None
                         for chunk in content.chunks():
-                            os.write(fd, chunk)
+                            if _file is None:
+                                mode = 'wb' if isinstance(chunk, bytes) else 'wt'
+                                _file = os.fdopen(fd, mode)
+                            _file.write(chunk)
                     finally:
                         locks.unlock(fd)
-                        os.close(fd)
+                        if _file is not None:
+                            _file.close()
+                        else:
+                            os.close(fd)
             except OSError as e:
                 if e.errno == errno.EEXIST:
                     # Ooops, the file exists. We need a new file name.

+ 11 - 0
tests/regressiontests/file_storage/tests.py

@@ -356,6 +356,17 @@ class FileStorageTests(unittest.TestCase):
         finally:
             os.remove = real_remove
 
+    def test_file_chunks_error(self):
+        """
+        Test behaviour when file.chunks() is raising an error
+        """
+        f1 = ContentFile('chunks fails')
+        def failing_chunks():
+            raise IOError
+        f1.chunks = failing_chunks
+        with self.assertRaises(IOError):
+            self.storage.save('error.file', f1)
+
 
 class CustomStorage(FileSystemStorage):
     def get_available_name(self, name):