mirror of https://github.com/django/django.git
Fixed #27777 -- Made File.open() work with the with statement
This commit is contained in:
parent
695d4dd790
commit
c4536c4a54
1
AUTHORS
1
AUTHORS
|
@ -324,6 +324,7 @@ answer newbie questions, and generally made Django that much better:
|
||||||
Igor Kolar <ike@email.si>
|
Igor Kolar <ike@email.si>
|
||||||
Illia Volochii <illia.volochii@gmail.com>
|
Illia Volochii <illia.volochii@gmail.com>
|
||||||
Ilya Semenov <semenov@inetss.com>
|
Ilya Semenov <semenov@inetss.com>
|
||||||
|
Ingo Klöcker <djangoproject@ingo-kloecker.de>
|
||||||
I.S. van Oostveen <v.oostveen@idca.nl>
|
I.S. van Oostveen <v.oostveen@idca.nl>
|
||||||
ivan.chelubeev@gmail.com
|
ivan.chelubeev@gmail.com
|
||||||
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/>
|
||||||
|
|
|
@ -125,6 +125,7 @@ class File(FileProxyMixin):
|
||||||
self.file = open(self.name, mode or self.mode)
|
self.file = open(self.name, mode or self.mode)
|
||||||
else:
|
else:
|
||||||
raise ValueError("The file cannot be reopened.")
|
raise ValueError("The file cannot be reopened.")
|
||||||
|
return self
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
@ -147,6 +148,7 @@ class ContentFile(File):
|
||||||
|
|
||||||
def open(self, mode=None):
|
def open(self, mode=None):
|
||||||
self.seek(0)
|
self.seek(0)
|
||||||
|
return self
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -85,6 +85,7 @@ class InMemoryUploadedFile(UploadedFile):
|
||||||
|
|
||||||
def open(self, mode=None):
|
def open(self, mode=None):
|
||||||
self.file.seek(0)
|
self.file.seek(0)
|
||||||
|
return self
|
||||||
|
|
||||||
def chunks(self, chunk_size=None):
|
def chunks(self, chunk_size=None):
|
||||||
self.file.seek(0)
|
self.file.seek(0)
|
||||||
|
|
|
@ -75,6 +75,7 @@ class FieldFile(File):
|
||||||
self.file.open(mode)
|
self.file.open(mode)
|
||||||
else:
|
else:
|
||||||
self.file = self.storage.open(self.name, mode)
|
self.file = self.storage.open(self.name, mode)
|
||||||
|
return self
|
||||||
# open() doesn't alter the file's contents, but it does reset the pointer
|
# open() doesn't alter the file's contents, but it does reset the pointer
|
||||||
open.alters_data = True
|
open.alters_data = True
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ The ``File`` class
|
||||||
was originally opened with; ``None`` means to reopen with the original
|
was originally opened with; ``None`` means to reopen with the original
|
||||||
mode.
|
mode.
|
||||||
|
|
||||||
|
Returns ``self``, so that it can be used similar to Python's
|
||||||
|
built-in :func:`python:open()` with the ``with`` statement.
|
||||||
|
|
||||||
.. method:: read(num_bytes=None)
|
.. method:: read(num_bytes=None)
|
||||||
|
|
||||||
Read content from the file. The optional ``size`` is the number of
|
Read content from the file. The optional ``size`` is the number of
|
||||||
|
|
|
@ -10,7 +10,9 @@ from django.core.files import File
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
from django.core.files.move import file_move_safe
|
from django.core.files.move import file_move_safe
|
||||||
from django.core.files.temp import NamedTemporaryFile
|
from django.core.files.temp import NamedTemporaryFile
|
||||||
from django.core.files.uploadedfile import SimpleUploadedFile, UploadedFile
|
from django.core.files.uploadedfile import (
|
||||||
|
InMemoryUploadedFile, SimpleUploadedFile, UploadedFile,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -38,6 +40,23 @@ class FileTests(unittest.TestCase):
|
||||||
self.assertTrue(f.closed)
|
self.assertTrue(f.closed)
|
||||||
self.assertTrue(orig_file.closed)
|
self.assertTrue(orig_file.closed)
|
||||||
|
|
||||||
|
def test_open_resets_opened_file_to_start_and_returns_context_manager(self):
|
||||||
|
file = File(BytesIO(b'content'))
|
||||||
|
file.read()
|
||||||
|
with file.open() as f:
|
||||||
|
self.assertEqual(f.read(), b'content')
|
||||||
|
|
||||||
|
def test_open_reopens_closed_file_and_returns_context_manager(self):
|
||||||
|
temporary_file = tempfile.NamedTemporaryFile(delete=False)
|
||||||
|
file = File(temporary_file)
|
||||||
|
try:
|
||||||
|
file.close()
|
||||||
|
with file.open() as f:
|
||||||
|
self.assertFalse(f.closed)
|
||||||
|
finally:
|
||||||
|
# remove temporary file
|
||||||
|
os.unlink(file.name)
|
||||||
|
|
||||||
def test_namedtemporaryfile_closes(self):
|
def test_namedtemporaryfile_closes(self):
|
||||||
"""
|
"""
|
||||||
The symbol django.core.files.NamedTemporaryFile is assigned as
|
The symbol django.core.files.NamedTemporaryFile is assigned as
|
||||||
|
@ -178,6 +197,21 @@ class ContentFileTestCase(unittest.TestCase):
|
||||||
self.assertIsInstance(ContentFile(b"content").read(), bytes)
|
self.assertIsInstance(ContentFile(b"content").read(), bytes)
|
||||||
self.assertIsInstance(ContentFile("español").read(), str)
|
self.assertIsInstance(ContentFile("español").read(), str)
|
||||||
|
|
||||||
|
def test_open_resets_file_to_start_and_returns_context_manager(self):
|
||||||
|
file = ContentFile(b'content')
|
||||||
|
with file.open() as f:
|
||||||
|
self.assertEqual(f.read(), b'content')
|
||||||
|
with file.open() as f:
|
||||||
|
self.assertEqual(f.read(), b'content')
|
||||||
|
|
||||||
|
|
||||||
|
class InMemoryUploadedFileTests(unittest.TestCase):
|
||||||
|
def test_open_resets_file_to_start_and_returns_context_manager(self):
|
||||||
|
uf = InMemoryUploadedFile(StringIO('1'), '', 'test', 'text/plain', 1, 'utf8')
|
||||||
|
uf.read()
|
||||||
|
with uf.open() as f:
|
||||||
|
self.assertEqual(f.read(), '1')
|
||||||
|
|
||||||
|
|
||||||
class DimensionClosingBug(unittest.TestCase):
|
class DimensionClosingBug(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue