diff options
| author | Ingo Klöcker <ingokloecker@users.noreply.github.com> | 2017-04-07 14:21:06 +0200 |
|---|---|---|
| committer | Florian Apolloner <apollo13@users.noreply.github.com> | 2017-04-07 14:21:06 +0200 |
| commit | c4536c4a54282cd89bc815b58cc3c73280712df1 (patch) | |
| tree | 3d425bbaaafe0cffd5d7ad19cf1f733fa805d975 | |
| parent | 695d4dd7908ca32e118716b474c23b43727579d2 (diff) | |
Fixed #27777 -- Made File.open() work with the with statement (#8310)
Fixed #27777 -- Made File.open() work with the with statement
| -rw-r--r-- | AUTHORS | 1 | ||||
| -rw-r--r-- | django/core/files/base.py | 2 | ||||
| -rw-r--r-- | django/core/files/uploadedfile.py | 1 | ||||
| -rw-r--r-- | django/db/models/fields/files.py | 1 | ||||
| -rw-r--r-- | docs/ref/files/file.txt | 3 | ||||
| -rw-r--r-- | tests/files/tests.py | 36 |
6 files changed, 43 insertions, 1 deletions
@@ -324,6 +324,7 @@ answer newbie questions, and generally made Django that much better: Igor Kolar <ike@email.si> Illia Volochii <illia.volochii@gmail.com> Ilya Semenov <semenov@inetss.com> + Ingo Klöcker <djangoproject@ingo-kloecker.de> I.S. van Oostveen <v.oostveen@idca.nl> ivan.chelubeev@gmail.com Ivan Sagalaev (Maniac) <http://www.softwaremaniacs.org/> diff --git a/django/core/files/base.py b/django/core/files/base.py index ff0a289dea..5e6332f0b6 100644 --- a/django/core/files/base.py +++ b/django/core/files/base.py @@ -125,6 +125,7 @@ class File(FileProxyMixin): self.file = open(self.name, mode or self.mode) else: raise ValueError("The file cannot be reopened.") + return self def close(self): self.file.close() @@ -147,6 +148,7 @@ class ContentFile(File): def open(self, mode=None): self.seek(0) + return self def close(self): pass diff --git a/django/core/files/uploadedfile.py b/django/core/files/uploadedfile.py index 485bfbfd6f..60c354a9f7 100644 --- a/django/core/files/uploadedfile.py +++ b/django/core/files/uploadedfile.py @@ -85,6 +85,7 @@ class InMemoryUploadedFile(UploadedFile): def open(self, mode=None): self.file.seek(0) + return self def chunks(self, chunk_size=None): self.file.seek(0) diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index 92e710299f..cbd0386435 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -75,6 +75,7 @@ class FieldFile(File): self.file.open(mode) else: 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.alters_data = True diff --git a/docs/ref/files/file.txt b/docs/ref/files/file.txt index 803f060c29..d79ae57f47 100644 --- a/docs/ref/files/file.txt +++ b/docs/ref/files/file.txt @@ -56,6 +56,9 @@ The ``File`` class was originally opened with; ``None`` means to reopen with the original 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) Read content from the file. The optional ``size`` is the number of diff --git a/tests/files/tests.py b/tests/files/tests.py index 9b3e019f8d..1a383090f9 100644 --- a/tests/files/tests.py +++ b/tests/files/tests.py @@ -10,7 +10,9 @@ from django.core.files import File from django.core.files.base import ContentFile from django.core.files.move import file_move_safe 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: from PIL import Image @@ -38,6 +40,23 @@ class FileTests(unittest.TestCase): self.assertTrue(f.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): """ 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("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): """ |
