Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Rearranged some file-related tests

Just moving around some tests to be more logically grouped.
  • Loading branch information...
commit 35db9d58d691d90b0c33e18b613067609d9e638f 1 parent 88f03db
Claude Paroz claudep authored
31 tests/file_storage/models.py
View
@@ -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)
269 tests/file_storage/tests.py
View
@@ -8,9 +8,7 @@
import tempfile
import time
import unittest
-import zlib
from datetime import datetime, timedelta
-from io import BytesIO
try:
import threading
@@ -18,21 +16,18 @@
import dummy_threading as threading
from django.conf import settings
+from django.core.cache import cache
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
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.core.files.uploadedfile import SimpleUploadedFile
from django.test import LiveServerTestCase, SimpleTestCase
from django.test.utils import override_settings
from django.utils import six
from django.utils.six.moves.urllib.request import urlopen
from django.utils._os import upath
-try:
- from django.utils.image import Image
-except ImproperlyConfigured:
- Image = None
+from .models import Storage, temp_storage, temp_storage_location
class GetStorageClassTests(SimpleTestCase):
@@ -396,15 +391,137 @@ def test_custom_get_available_name(self):
self.storage.delete(first)
self.storage.delete(second)
-class UnicodeFileNameTests(unittest.TestCase):
- def test_unicode_file_names(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)
+
+class FileFieldStorageTests(unittest.TestCase):
+ def tearDown(self):
+ shutil.rmtree(temp_storage_location)
+
+ def test_files(self):
+ # 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.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).
# This is written in such a way that it'll always pass on platforms
@@ -508,91 +625,8 @@ def test_first_character_dot(self):
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')))
-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")
- 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):
+class ContentFileStorageTestCase(unittest.TestCase):
def setUp(self):
self.storage_dir = tempfile.mkdtemp()
@@ -601,27 +635,6 @@ def setUp(self):
def tearDown(self):
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):
"""
Test that ContentFile can be saved correctly with the filesystem storage,
@@ -630,18 +643,6 @@ def test_content_saving(self):
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):
"""
Test file-like objects (#15644).
0  tests/file_storage/magic.png → tests/files/magic.png
View
File renamed without changes
31 tests/files/models.py
View
@@ -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)
0  tests/file_storage/test.png → tests/files/test.png
View
File renamed without changes
0  tests/file_storage/test1.png → tests/files/test1.png
View
File renamed without changes
268 tests/files/tests.py
View
@@ -1,147 +1,41 @@
+# -*- coding: utf-8 -*-
from __future__ import unicode_literals
+from io import BytesIO
import os
import gzip
import shutil
import tempfile
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.move import file_move_safe
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.test import TestCase
-from django.utils.six import StringIO
-
-from .models import Storage, temp_storage, temp_storage_location
-
-
-class FileStorageTests(TestCase):
- def tearDown(self):
- 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')
+from django.utils._os import upath
+from django.utils import six
+
+try:
+ from django.utils.image import Image
+ from django.core.files import images
+except ImproperlyConfigured:
+ Image = None
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):
orig_file = tempfile.TemporaryFile()
base_file = File(orig_file)
@@ -173,6 +67,124 @@ def test_file_mode(self):
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):
def test_file_move_overwrite(self):
handle_a, self.file_a = tempfile.mkstemp(dir=os.environ['DJANGO_TEST_TEMP_DIR'])
Please sign in to comment.
Something went wrong with that request. Please try again.