Rearranged some file-related tests
Just moving around some tests to be more logically grouped.
This commit is contained in:
parent
88f03db05f
commit
35db9d58d6
|
@ -0,0 +1,31 @@
|
||||||
|
"""
|
||||||
|
42. Storing files according to a custom storage system
|
||||||
|
|
||||||
|
``FileField`` and its variations can take a ``storage`` argument to specify how
|
||||||
|
and where files should be stored.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.core.files.storage import FileSystemStorage
|
||||||
|
|
||||||
|
|
||||||
|
temp_storage_location = tempfile.mkdtemp()
|
||||||
|
temp_storage = FileSystemStorage(location=temp_storage_location)
|
||||||
|
|
||||||
|
class Storage(models.Model):
|
||||||
|
def custom_upload_to(self, filename):
|
||||||
|
return 'foo'
|
||||||
|
|
||||||
|
def random_upload_to(self, filename):
|
||||||
|
# This returns a different result each time,
|
||||||
|
# to make sure it only gets called once.
|
||||||
|
return '%s/%s' % (random.randint(100, 999), filename)
|
||||||
|
|
||||||
|
normal = models.FileField(storage=temp_storage, upload_to='tests')
|
||||||
|
custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
|
||||||
|
random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
|
||||||
|
default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
|
||||||
|
empty = models.FileField(storage=temp_storage)
|
|
@ -8,9 +8,7 @@ import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
import zlib
|
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import threading
|
import threading
|
||||||
|
@ -18,21 +16,18 @@ except ImportError:
|
||||||
import dummy_threading as threading
|
import dummy_threading as threading
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.cache import cache
|
||||||
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
|
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
|
||||||
from django.core.files.base import File, 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.storage import FileSystemStorage, get_storage_class
|
||||||
from django.core.files.uploadedfile import UploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.test import LiveServerTestCase, SimpleTestCase
|
from django.test import LiveServerTestCase, SimpleTestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.six.moves.urllib.request import urlopen
|
from django.utils.six.moves.urllib.request import urlopen
|
||||||
from django.utils._os import upath
|
from django.utils._os import upath
|
||||||
|
|
||||||
try:
|
from .models import Storage, temp_storage, temp_storage_location
|
||||||
from django.utils.image import Image
|
|
||||||
except ImproperlyConfigured:
|
|
||||||
Image = None
|
|
||||||
|
|
||||||
|
|
||||||
class GetStorageClassTests(SimpleTestCase):
|
class GetStorageClassTests(SimpleTestCase):
|
||||||
|
@ -396,15 +391,137 @@ class CustomStorageTests(FileStorageTests):
|
||||||
self.storage.delete(first)
|
self.storage.delete(first)
|
||||||
self.storage.delete(second)
|
self.storage.delete(second)
|
||||||
|
|
||||||
class UnicodeFileNameTests(unittest.TestCase):
|
|
||||||
def test_unicode_file_names(self):
|
class FileFieldStorageTests(unittest.TestCase):
|
||||||
"""
|
def tearDown(self):
|
||||||
Regression test for #8156: files with unicode names I can't quite figure
|
shutil.rmtree(temp_storage_location)
|
||||||
out the encoding situation between doctest and this file, but the actual
|
|
||||||
repr doesn't matter; it just shouldn't return a unicode object.
|
def test_files(self):
|
||||||
"""
|
# Attempting to access a FileField from the class raises a descriptive
|
||||||
uf = UploadedFile(name='¿Cómo?', content_type='text')
|
# error
|
||||||
self.assertEqual(type(uf.__repr__()), str)
|
self.assertRaises(AttributeError, lambda: Storage.normal)
|
||||||
|
|
||||||
|
# An object without a file has limited functionality.
|
||||||
|
obj1 = Storage()
|
||||||
|
self.assertEqual(obj1.normal.name, "")
|
||||||
|
self.assertRaises(ValueError, lambda: obj1.normal.size)
|
||||||
|
|
||||||
|
# Saving a file enables full functionality.
|
||||||
|
obj1.normal.save("django_test.txt", ContentFile("content"))
|
||||||
|
self.assertEqual(obj1.normal.name, "tests/django_test.txt")
|
||||||
|
self.assertEqual(obj1.normal.size, 7)
|
||||||
|
self.assertEqual(obj1.normal.read(), b"content")
|
||||||
|
obj1.normal.close()
|
||||||
|
|
||||||
|
# File objects can be assigned to FileField attributes, but shouldn't
|
||||||
|
# get committed until the model it's attached to is saved.
|
||||||
|
obj1.normal = SimpleUploadedFile("assignment.txt", b"content")
|
||||||
|
dirs, files = temp_storage.listdir("tests")
|
||||||
|
self.assertEqual(dirs, [])
|
||||||
|
self.assertFalse("assignment.txt" in files)
|
||||||
|
|
||||||
|
obj1.save()
|
||||||
|
dirs, files = temp_storage.listdir("tests")
|
||||||
|
self.assertEqual(sorted(files), ["assignment.txt", "django_test.txt"])
|
||||||
|
|
||||||
|
# Save another file with the same name.
|
||||||
|
obj2 = Storage()
|
||||||
|
obj2.normal.save("django_test.txt", ContentFile("more content"))
|
||||||
|
self.assertEqual(obj2.normal.name, "tests/django_test_1.txt")
|
||||||
|
self.assertEqual(obj2.normal.size, 12)
|
||||||
|
obj2.normal.close()
|
||||||
|
|
||||||
|
# Deleting an object does not delete the file it uses.
|
||||||
|
obj2.delete()
|
||||||
|
obj2.normal.save("django_test.txt", ContentFile("more content"))
|
||||||
|
self.assertEqual(obj2.normal.name, "tests/django_test_2.txt")
|
||||||
|
obj2.normal.close()
|
||||||
|
|
||||||
|
def test_filefield_read(self):
|
||||||
|
# Files can be read in a little at a time, if necessary.
|
||||||
|
obj = Storage.objects.create(
|
||||||
|
normal=SimpleUploadedFile("assignment.txt", b"content"))
|
||||||
|
obj.normal.open()
|
||||||
|
self.assertEqual(obj.normal.read(3), b"con")
|
||||||
|
self.assertEqual(obj.normal.read(), b"tent")
|
||||||
|
self.assertEqual(list(obj.normal.chunks(chunk_size=2)), [b"co", b"nt", b"en", b"t"])
|
||||||
|
obj.normal.close()
|
||||||
|
|
||||||
|
def test_file_numbering(self):
|
||||||
|
# Multiple files with the same name get _N appended to them.
|
||||||
|
objs = [Storage() for i in range(3)]
|
||||||
|
for o in objs:
|
||||||
|
o.normal.save("multiple_files.txt", ContentFile("Same Content"))
|
||||||
|
self.assertEqual(
|
||||||
|
[o.normal.name for o in objs],
|
||||||
|
["tests/multiple_files.txt", "tests/multiple_files_1.txt", "tests/multiple_files_2.txt"]
|
||||||
|
)
|
||||||
|
for o in objs:
|
||||||
|
o.delete()
|
||||||
|
|
||||||
|
def test_filefield_default(self):
|
||||||
|
# Default values allow an object to access a single file.
|
||||||
|
temp_storage.save('tests/default.txt', ContentFile('default content'))
|
||||||
|
obj = Storage.objects.create()
|
||||||
|
self.assertEqual(obj.default.name, "tests/default.txt")
|
||||||
|
self.assertEqual(obj.default.read(), b"default content")
|
||||||
|
obj.default.close()
|
||||||
|
|
||||||
|
# But it shouldn't be deleted, even if there are no more objects using
|
||||||
|
# it.
|
||||||
|
obj.delete()
|
||||||
|
obj = Storage()
|
||||||
|
self.assertEqual(obj.default.read(), b"default content")
|
||||||
|
obj.default.close()
|
||||||
|
|
||||||
|
def test_empty_upload_to(self):
|
||||||
|
# upload_to can be empty, meaning it does not use subdirectory.
|
||||||
|
obj = Storage()
|
||||||
|
obj.empty.save('django_test.txt', ContentFile('more content'))
|
||||||
|
self.assertEqual(obj.empty.name, "./django_test.txt")
|
||||||
|
self.assertEqual(obj.empty.read(), b"more content")
|
||||||
|
obj.empty.close()
|
||||||
|
|
||||||
|
def test_random_upload_to(self):
|
||||||
|
# Verify the fix for #5655, making sure the directory is only
|
||||||
|
# determined once.
|
||||||
|
obj = Storage()
|
||||||
|
obj.random.save("random_file", ContentFile("random content"))
|
||||||
|
self.assertTrue(obj.random.name.endswith("/random_file"))
|
||||||
|
obj.random.close()
|
||||||
|
|
||||||
|
def test_filefield_pickling(self):
|
||||||
|
# Push an object into the cache to make sure it pickles properly
|
||||||
|
obj = Storage()
|
||||||
|
obj.normal.save("django_test.txt", ContentFile("more content"))
|
||||||
|
obj.normal.close()
|
||||||
|
cache.set("obj", obj)
|
||||||
|
self.assertEqual(cache.get("obj").normal.name, "tests/django_test.txt")
|
||||||
|
|
||||||
|
def test_file_object(self):
|
||||||
|
# Create sample file
|
||||||
|
temp_storage.save('tests/example.txt', ContentFile('some content'))
|
||||||
|
|
||||||
|
# Load it as python file object
|
||||||
|
with open(temp_storage.path('tests/example.txt')) as file_obj:
|
||||||
|
# Save it using storage and read its content
|
||||||
|
temp_storage.save('tests/file_obj', file_obj)
|
||||||
|
self.assertTrue(temp_storage.exists('tests/file_obj'))
|
||||||
|
with temp_storage.open('tests/file_obj') as f:
|
||||||
|
self.assertEqual(f.read(), b'some content')
|
||||||
|
|
||||||
|
def test_stringio(self):
|
||||||
|
# Test passing StringIO instance as content argument to save
|
||||||
|
output = six.StringIO()
|
||||||
|
output.write('content')
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
|
# Save it and read written file
|
||||||
|
temp_storage.save('tests/stringio', output)
|
||||||
|
self.assertTrue(temp_storage.exists('tests/stringio'))
|
||||||
|
with temp_storage.open('tests/stringio') as f:
|
||||||
|
self.assertEqual(f.read(), b'content')
|
||||||
|
|
||||||
|
|
||||||
# Tests for a race condition on file saving (#4948).
|
# Tests for a race condition on file saving (#4948).
|
||||||
# This is written in such a way that it'll always pass on platforms
|
# This is written in such a way that it'll always pass on platforms
|
||||||
|
@ -508,91 +625,8 @@ class FileStoragePathParsing(unittest.TestCase):
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
|
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test')))
|
||||||
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_1')))
|
self.assertTrue(os.path.exists(os.path.join(self.storage_dir, 'dotted.path/.test_1')))
|
||||||
|
|
||||||
class DimensionClosingBug(unittest.TestCase):
|
|
||||||
"""
|
|
||||||
Test that get_image_dimensions() properly closes files (#8817)
|
|
||||||
"""
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
|
||||||
def test_not_closing_of_files(self):
|
|
||||||
"""
|
|
||||||
Open files passed into get_image_dimensions() should stay opened.
|
|
||||||
"""
|
|
||||||
empty_io = BytesIO()
|
|
||||||
try:
|
|
||||||
get_image_dimensions(empty_io)
|
|
||||||
finally:
|
|
||||||
self.assertTrue(not empty_io.closed)
|
|
||||||
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
class ContentFileStorageTestCase(unittest.TestCase):
|
||||||
def test_closing_of_filenames(self):
|
|
||||||
"""
|
|
||||||
get_image_dimensions() called with a filename should closed the file.
|
|
||||||
"""
|
|
||||||
# We need to inject a modified open() builtin into the images module
|
|
||||||
# that checks if the file was closed properly if the function is
|
|
||||||
# called with a filename instead of an file object.
|
|
||||||
# get_image_dimensions will call our catching_open instead of the
|
|
||||||
# regular builtin one.
|
|
||||||
|
|
||||||
class FileWrapper(object):
|
|
||||||
_closed = []
|
|
||||||
|
|
||||||
def __init__(self, f):
|
|
||||||
self.f = f
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
|
||||||
return getattr(self.f, name)
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
self._closed.append(True)
|
|
||||||
self.f.close()
|
|
||||||
|
|
||||||
def catching_open(*args):
|
|
||||||
return FileWrapper(open(*args))
|
|
||||||
|
|
||||||
from django.core.files import images
|
|
||||||
images.open = catching_open
|
|
||||||
try:
|
|
||||||
get_image_dimensions(os.path.join(os.path.dirname(upath(__file__)), "test1.png"))
|
|
||||||
finally:
|
|
||||||
del images.open
|
|
||||||
self.assertTrue(FileWrapper._closed)
|
|
||||||
|
|
||||||
class InconsistentGetImageDimensionsBug(unittest.TestCase):
|
|
||||||
"""
|
|
||||||
Test that get_image_dimensions() works properly after various calls
|
|
||||||
using a file handler (#11158)
|
|
||||||
"""
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
|
||||||
def test_multiple_calls(self):
|
|
||||||
"""
|
|
||||||
Multiple calls of get_image_dimensions() should return the same size.
|
|
||||||
"""
|
|
||||||
from django.core.files.images import ImageFile
|
|
||||||
|
|
||||||
img_path = os.path.join(os.path.dirname(upath(__file__)), "test.png")
|
|
||||||
with open(img_path, 'rb') as file:
|
|
||||||
image = ImageFile(file)
|
|
||||||
image_pil = Image.open(img_path)
|
|
||||||
size_1, size_2 = get_image_dimensions(image), get_image_dimensions(image)
|
|
||||||
self.assertEqual(image_pil.size, size_1)
|
|
||||||
self.assertEqual(size_1, size_2)
|
|
||||||
|
|
||||||
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
|
||||||
def test_bug_19457(self):
|
|
||||||
"""
|
|
||||||
Regression test for #19457
|
|
||||||
get_image_dimensions fails on some pngs, while Image.size is working good on them
|
|
||||||
"""
|
|
||||||
img_path = os.path.join(os.path.dirname(upath(__file__)), "magic.png")
|
|
||||||
try:
|
|
||||||
size = get_image_dimensions(img_path)
|
|
||||||
except zlib.error:
|
|
||||||
self.fail("Exception raised from get_image_dimensions().")
|
|
||||||
self.assertEqual(size, Image.open(img_path).size)
|
|
||||||
|
|
||||||
|
|
||||||
class ContentFileTestCase(unittest.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.storage_dir = tempfile.mkdtemp()
|
self.storage_dir = tempfile.mkdtemp()
|
||||||
|
@ -601,27 +635,6 @@ class ContentFileTestCase(unittest.TestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
shutil.rmtree(self.storage_dir)
|
shutil.rmtree(self.storage_dir)
|
||||||
|
|
||||||
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.assertIsInstance(ContentFile(b"content").read(), bytes)
|
|
||||||
if six.PY3:
|
|
||||||
self.assertIsInstance(ContentFile("español").read(), six.text_type)
|
|
||||||
else:
|
|
||||||
self.assertIsInstance(ContentFile("español").read(), bytes)
|
|
||||||
|
|
||||||
def test_content_saving(self):
|
def test_content_saving(self):
|
||||||
"""
|
"""
|
||||||
Test that ContentFile can be saved correctly with the filesystem storage,
|
Test that ContentFile can be saved correctly with the filesystem storage,
|
||||||
|
@ -630,18 +643,6 @@ class ContentFileTestCase(unittest.TestCase):
|
||||||
self.storage.save('unicode.txt', ContentFile("español"))
|
self.storage.save('unicode.txt', ContentFile("español"))
|
||||||
|
|
||||||
|
|
||||||
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(BytesIO(b'A file with no name')).name, None)
|
|
||||||
|
|
||||||
def test_noname_file_get_size(self):
|
|
||||||
self.assertEqual(File(BytesIO(b'A file with no name')).size, 19)
|
|
||||||
|
|
||||||
|
|
||||||
class FileLikeObjectTestCase(LiveServerTestCase):
|
class FileLikeObjectTestCase(LiveServerTestCase):
|
||||||
"""
|
"""
|
||||||
Test file-like objects (#15644).
|
Test file-like objects (#15644).
|
||||||
|
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
@ -1,31 +0,0 @@
|
||||||
"""
|
|
||||||
42. Storing files according to a custom storage system
|
|
||||||
|
|
||||||
``FileField`` and its variations can take a ``storage`` argument to specify how
|
|
||||||
and where files should be stored.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import random
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
from django.db import models
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
|
|
||||||
|
|
||||||
temp_storage_location = tempfile.mkdtemp()
|
|
||||||
temp_storage = FileSystemStorage(location=temp_storage_location)
|
|
||||||
|
|
||||||
class Storage(models.Model):
|
|
||||||
def custom_upload_to(self, filename):
|
|
||||||
return 'foo'
|
|
||||||
|
|
||||||
def random_upload_to(self, filename):
|
|
||||||
# This returns a different result each time,
|
|
||||||
# to make sure it only gets called once.
|
|
||||||
return '%s/%s' % (random.randint(100, 999), filename)
|
|
||||||
|
|
||||||
normal = models.FileField(storage=temp_storage, upload_to='tests')
|
|
||||||
custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
|
|
||||||
random = models.FileField(storage=temp_storage, upload_to=random_upload_to)
|
|
||||||
default = models.FileField(storage=temp_storage, upload_to='tests', default='tests/default.txt')
|
|
||||||
empty = models.FileField(storage=temp_storage)
|
|
Before Width: | Height: | Size: 482 B After Width: | Height: | Size: 482 B |
Before Width: | Height: | Size: 480 B After Width: | Height: | Size: 480 B |
|
@ -1,147 +1,41 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from io import BytesIO
|
||||||
import os
|
import os
|
||||||
import gzip
|
import gzip
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
import zlib
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.core.files.move import file_move_safe
|
from django.core.files.move import file_move_safe
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
from django.core.files.uploadedfile import SimpleUploadedFile, UploadedFile
|
||||||
from django.core.files.temp import NamedTemporaryFile
|
from django.core.files.temp import NamedTemporaryFile
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils.six import StringIO
|
from django.utils._os import upath
|
||||||
|
from django.utils import six
|
||||||
|
|
||||||
from .models import Storage, temp_storage, temp_storage_location
|
try:
|
||||||
|
from django.utils.image import Image
|
||||||
|
from django.core.files import images
|
||||||
class FileStorageTests(TestCase):
|
except ImproperlyConfigured:
|
||||||
def tearDown(self):
|
Image = None
|
||||||
shutil.rmtree(temp_storage_location)
|
|
||||||
|
|
||||||
def test_files(self):
|
|
||||||
temp_storage.save('tests/default.txt', ContentFile('default content'))
|
|
||||||
# Attempting to access a FileField from the class raises a descriptive
|
|
||||||
# error
|
|
||||||
self.assertRaises(AttributeError, lambda: Storage.normal)
|
|
||||||
|
|
||||||
# An object without a file has limited functionality.
|
|
||||||
obj1 = Storage()
|
|
||||||
self.assertEqual(obj1.normal.name, "")
|
|
||||||
self.assertRaises(ValueError, lambda: obj1.normal.size)
|
|
||||||
|
|
||||||
# Saving a file enables full functionality.
|
|
||||||
obj1.normal.save("django_test.txt", ContentFile("content"))
|
|
||||||
self.assertEqual(obj1.normal.name, "tests/django_test.txt")
|
|
||||||
self.assertEqual(obj1.normal.size, 7)
|
|
||||||
self.assertEqual(obj1.normal.read(), b"content")
|
|
||||||
obj1.normal.close()
|
|
||||||
|
|
||||||
# File objects can be assigned to FileField attributes, but shouldn't
|
|
||||||
# get committed until the model it's attached to is saved.
|
|
||||||
obj1.normal = SimpleUploadedFile("assignment.txt", b"content")
|
|
||||||
dirs, files = temp_storage.listdir("tests")
|
|
||||||
self.assertEqual(dirs, [])
|
|
||||||
self.assertEqual(sorted(files), ["default.txt", "django_test.txt"])
|
|
||||||
|
|
||||||
obj1.save()
|
|
||||||
dirs, files = temp_storage.listdir("tests")
|
|
||||||
self.assertEqual(
|
|
||||||
sorted(files), ["assignment.txt", "default.txt", "django_test.txt"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Files can be read in a little at a time, if necessary.
|
|
||||||
obj1.normal.open()
|
|
||||||
self.assertEqual(obj1.normal.read(3), b"con")
|
|
||||||
self.assertEqual(obj1.normal.read(), b"tent")
|
|
||||||
self.assertEqual(list(obj1.normal.chunks(chunk_size=2)), [b"co", b"nt", b"en", b"t"])
|
|
||||||
obj1.normal.close()
|
|
||||||
|
|
||||||
# Save another file with the same name.
|
|
||||||
obj2 = Storage()
|
|
||||||
obj2.normal.save("django_test.txt", ContentFile("more content"))
|
|
||||||
self.assertEqual(obj2.normal.name, "tests/django_test_1.txt")
|
|
||||||
self.assertEqual(obj2.normal.size, 12)
|
|
||||||
obj2.normal.close()
|
|
||||||
|
|
||||||
# Push the objects into the cache to make sure they pickle properly
|
|
||||||
cache.set("obj1", obj1)
|
|
||||||
cache.set("obj2", obj2)
|
|
||||||
self.assertEqual(cache.get("obj2").normal.name, "tests/django_test_1.txt")
|
|
||||||
|
|
||||||
# Deleting an object does not delete the file it uses.
|
|
||||||
obj2.delete()
|
|
||||||
obj2.normal.save("django_test.txt", ContentFile("more content"))
|
|
||||||
self.assertEqual(obj2.normal.name, "tests/django_test_2.txt")
|
|
||||||
obj2.normal.close()
|
|
||||||
|
|
||||||
# Multiple files with the same name get _N appended to them.
|
|
||||||
objs = [Storage() for i in range(3)]
|
|
||||||
for o in objs:
|
|
||||||
o.normal.save("multiple_files.txt", ContentFile("Same Content"))
|
|
||||||
self.assertEqual(
|
|
||||||
[o.normal.name for o in objs],
|
|
||||||
["tests/multiple_files.txt", "tests/multiple_files_1.txt", "tests/multiple_files_2.txt"]
|
|
||||||
)
|
|
||||||
for o in objs:
|
|
||||||
o.delete()
|
|
||||||
|
|
||||||
# Default values allow an object to access a single file.
|
|
||||||
obj3 = Storage.objects.create()
|
|
||||||
self.assertEqual(obj3.default.name, "tests/default.txt")
|
|
||||||
self.assertEqual(obj3.default.read(), b"default content")
|
|
||||||
obj3.default.close()
|
|
||||||
|
|
||||||
# But it shouldn't be deleted, even if there are no more objects using
|
|
||||||
# it.
|
|
||||||
obj3.delete()
|
|
||||||
obj3 = Storage()
|
|
||||||
self.assertEqual(obj3.default.read(), b"default content")
|
|
||||||
obj3.default.close()
|
|
||||||
|
|
||||||
# Verify the fix for #5655, making sure the directory is only
|
|
||||||
# determined once.
|
|
||||||
obj4 = Storage()
|
|
||||||
obj4.random.save("random_file", ContentFile("random content"))
|
|
||||||
self.assertTrue(obj4.random.name.endswith("/random_file"))
|
|
||||||
obj4.random.close()
|
|
||||||
|
|
||||||
# upload_to can be empty, meaning it does not use subdirectory.
|
|
||||||
obj5 = Storage()
|
|
||||||
obj5.empty.save('django_test.txt', ContentFile('more content'))
|
|
||||||
self.assertEqual(obj5.empty.name, "./django_test.txt")
|
|
||||||
self.assertEqual(obj5.empty.read(), b"more content")
|
|
||||||
obj5.empty.close()
|
|
||||||
|
|
||||||
def test_file_object(self):
|
|
||||||
# Create sample file
|
|
||||||
temp_storage.save('tests/example.txt', ContentFile('some content'))
|
|
||||||
|
|
||||||
# Load it as python file object
|
|
||||||
with open(temp_storage.path('tests/example.txt')) as file_obj:
|
|
||||||
# Save it using storage and read its content
|
|
||||||
temp_storage.save('tests/file_obj', file_obj)
|
|
||||||
self.assertTrue(temp_storage.exists('tests/file_obj'))
|
|
||||||
with temp_storage.open('tests/file_obj') as f:
|
|
||||||
self.assertEqual(f.read(), b'some content')
|
|
||||||
|
|
||||||
def test_stringio(self):
|
|
||||||
# Test passing StringIO instance as content argument to save
|
|
||||||
output = StringIO()
|
|
||||||
output.write('content')
|
|
||||||
output.seek(0)
|
|
||||||
|
|
||||||
# Save it and read written file
|
|
||||||
temp_storage.save('tests/stringio', output)
|
|
||||||
self.assertTrue(temp_storage.exists('tests/stringio'))
|
|
||||||
with temp_storage.open('tests/stringio') as f:
|
|
||||||
self.assertEqual(f.read(), b'content')
|
|
||||||
|
|
||||||
|
|
||||||
class FileTests(unittest.TestCase):
|
class FileTests(unittest.TestCase):
|
||||||
|
def test_unicode_uploadedfile_name(self):
|
||||||
|
"""
|
||||||
|
Regression test for #8156: files with unicode names I can't quite figure
|
||||||
|
out the encoding situation between doctest and this file, but the actual
|
||||||
|
repr doesn't matter; it just shouldn't return a unicode object.
|
||||||
|
"""
|
||||||
|
uf = UploadedFile(name='¿Cómo?', content_type='text')
|
||||||
|
self.assertEqual(type(uf.__repr__()), str)
|
||||||
|
|
||||||
def test_context_manager(self):
|
def test_context_manager(self):
|
||||||
orig_file = tempfile.TemporaryFile()
|
orig_file = tempfile.TemporaryFile()
|
||||||
base_file = File(orig_file)
|
base_file = File(orig_file)
|
||||||
|
@ -173,6 +67,124 @@ class FileTests(unittest.TestCase):
|
||||||
gzip.GzipFile(fileobj=file)
|
gzip.GzipFile(fileobj=file)
|
||||||
|
|
||||||
|
|
||||||
|
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(BytesIO(b'A file with no name')).name, None)
|
||||||
|
|
||||||
|
def test_noname_file_get_size(self):
|
||||||
|
self.assertEqual(File(BytesIO(b'A file with no name')).size, 19)
|
||||||
|
|
||||||
|
|
||||||
|
class ContentFileTestCase(unittest.TestCase):
|
||||||
|
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.assertIsInstance(ContentFile(b"content").read(), bytes)
|
||||||
|
if six.PY3:
|
||||||
|
self.assertIsInstance(ContentFile("español").read(), six.text_type)
|
||||||
|
else:
|
||||||
|
self.assertIsInstance(ContentFile("español").read(), bytes)
|
||||||
|
|
||||||
|
|
||||||
|
class DimensionClosingBug(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Test that get_image_dimensions() properly closes files (#8817)
|
||||||
|
"""
|
||||||
|
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
||||||
|
def test_not_closing_of_files(self):
|
||||||
|
"""
|
||||||
|
Open files passed into get_image_dimensions() should stay opened.
|
||||||
|
"""
|
||||||
|
empty_io = BytesIO()
|
||||||
|
try:
|
||||||
|
images.get_image_dimensions(empty_io)
|
||||||
|
finally:
|
||||||
|
self.assertTrue(not empty_io.closed)
|
||||||
|
|
||||||
|
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
||||||
|
def test_closing_of_filenames(self):
|
||||||
|
"""
|
||||||
|
get_image_dimensions() called with a filename should closed the file.
|
||||||
|
"""
|
||||||
|
# We need to inject a modified open() builtin into the images module
|
||||||
|
# that checks if the file was closed properly if the function is
|
||||||
|
# called with a filename instead of an file object.
|
||||||
|
# get_image_dimensions will call our catching_open instead of the
|
||||||
|
# regular builtin one.
|
||||||
|
|
||||||
|
class FileWrapper(object):
|
||||||
|
_closed = []
|
||||||
|
|
||||||
|
def __init__(self, f):
|
||||||
|
self.f = f
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self.f, name)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._closed.append(True)
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
def catching_open(*args):
|
||||||
|
return FileWrapper(open(*args))
|
||||||
|
|
||||||
|
images.open = catching_open
|
||||||
|
try:
|
||||||
|
images.get_image_dimensions(os.path.join(os.path.dirname(upath(__file__)), "test1.png"))
|
||||||
|
finally:
|
||||||
|
del images.open
|
||||||
|
self.assertTrue(FileWrapper._closed)
|
||||||
|
|
||||||
|
|
||||||
|
class InconsistentGetImageDimensionsBug(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
Test that get_image_dimensions() works properly after various calls
|
||||||
|
using a file handler (#11158)
|
||||||
|
"""
|
||||||
|
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
||||||
|
def test_multiple_calls(self):
|
||||||
|
"""
|
||||||
|
Multiple calls of get_image_dimensions() should return the same size.
|
||||||
|
"""
|
||||||
|
img_path = os.path.join(os.path.dirname(upath(__file__)), "test.png")
|
||||||
|
with open(img_path, 'rb') as file:
|
||||||
|
image = images.ImageFile(file)
|
||||||
|
image_pil = Image.open(img_path)
|
||||||
|
size_1 = images.get_image_dimensions(image)
|
||||||
|
size_2 = images.get_image_dimensions(image)
|
||||||
|
self.assertEqual(image_pil.size, size_1)
|
||||||
|
self.assertEqual(size_1, size_2)
|
||||||
|
|
||||||
|
@unittest.skipUnless(Image, "Pillow/PIL not installed")
|
||||||
|
def test_bug_19457(self):
|
||||||
|
"""
|
||||||
|
Regression test for #19457
|
||||||
|
get_image_dimensions fails on some pngs, while Image.size is working good on them
|
||||||
|
"""
|
||||||
|
img_path = os.path.join(os.path.dirname(upath(__file__)), "magic.png")
|
||||||
|
try:
|
||||||
|
size = images.get_image_dimensions(img_path)
|
||||||
|
except zlib.error:
|
||||||
|
self.fail("Exception raised from get_image_dimensions().")
|
||||||
|
self.assertEqual(size, Image.open(img_path).size)
|
||||||
|
|
||||||
|
|
||||||
class FileMoveSafeTests(unittest.TestCase):
|
class FileMoveSafeTests(unittest.TestCase):
|
||||||
def test_file_move_overwrite(self):
|
def test_file_move_overwrite(self):
|
||||||
handle_a, self.file_a = tempfile.mkstemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
|
handle_a, self.file_a = tempfile.mkstemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
|
||||||
|
|
Loading…
Reference in New Issue