Loading django/http/response.py +7 −4 Original line number Diff line number Diff line Loading @@ -316,13 +316,16 @@ class HttpResponse(HttpResponseBase): def content(self, value): # Consume iterators upon assignment to allow repeated iteration. if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)): content = b''.join(self.make_bytes(chunk) for chunk in value) if hasattr(value, 'close'): self._closable_objects.append(value) value = b''.join(self.make_bytes(chunk) for chunk in value) try: value.close() except Exception: pass else: value = self.make_bytes(value) content = self.make_bytes(value) # Create a list of properly encoded bytestrings to support write(). self._container = [value] self._container = [content] def __iter__(self): return iter(self._container) Loading docs/ref/request-response.txt +7 −1 Original line number Diff line number Diff line Loading @@ -608,11 +608,17 @@ Passing iterators Finally, you can pass ``HttpResponse`` an iterator rather than strings. ``HttpResponse`` will consume the iterator immediately, store its content as a string, and discard it. string, and discard it. Objects with a ``close()`` method such as files and generators are immediately closed. If you need the response to be streamed from the iterator to the client, you must use the :class:`StreamingHttpResponse` class instead. .. versionchanged:: 1.10 Objects with a ``close()`` method used to be closed when the WSGI server called ``close()`` on the response. Setting header fields ~~~~~~~~~~~~~~~~~~~~~ Loading docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,10 @@ Miscellaneous * The ``add_postgis_srs()`` backwards compatibility alias for ``django.contrib.gis.utils.add_srs_entry()`` is removed. * Objects with a ``close()`` method such as files and generators passed to :class:`~django.http.HttpResponse` are now closed immediately instead of when the WSGI server calls ``close()`` on the response. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading tests/httpwrappers/tests.py +0 −13 Original line number Diff line number Diff line Loading @@ -588,18 +588,8 @@ class FileCloseTests(SimpleTestCase): # file isn't closed until we close the response. file1 = open(filename) r = HttpResponse(file1) self.assertFalse(file1.closed) r.close() self.assertTrue(file1.closed) # don't automatically close file when we finish iterating the response. file1 = open(filename) r = HttpResponse(file1) self.assertFalse(file1.closed) list(r) self.assertFalse(file1.closed) r.close() self.assertTrue(file1.closed) # when multiple file are assigned as content, make sure they are all # closed with the response. Loading @@ -607,9 +597,6 @@ class FileCloseTests(SimpleTestCase): file2 = open(filename) r = HttpResponse(file1) r.content = file2 self.assertFalse(file1.closed) self.assertFalse(file2.closed) r.close() self.assertTrue(file1.closed) self.assertTrue(file2.closed) Loading tests/responses/tests.py +11 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ from __future__ import unicode_literals import io from django.conf import settings from django.core.cache import cache from django.http import HttpResponse from django.http.response import HttpResponseBase from django.test import SimpleTestCase Loading Loading @@ -121,3 +122,13 @@ class HttpResponseTests(SimpleTestCase): with io.TextIOWrapper(r, UTF8) as buf: buf.write(content) self.assertEqual(r.content, content.encode(UTF8)) def test_generator_cache(self): generator = ("{}".format(i) for i in range(10)) response = HttpResponse(content=generator) self.assertEqual(response.content, b'0123456789') self.assertRaises(StopIteration, next, generator) cache.set('my-response-key', response) response = cache.get('my-response-key') self.assertEqual(response.content, b'0123456789') Loading
django/http/response.py +7 −4 Original line number Diff line number Diff line Loading @@ -316,13 +316,16 @@ class HttpResponse(HttpResponseBase): def content(self, value): # Consume iterators upon assignment to allow repeated iteration. if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)): content = b''.join(self.make_bytes(chunk) for chunk in value) if hasattr(value, 'close'): self._closable_objects.append(value) value = b''.join(self.make_bytes(chunk) for chunk in value) try: value.close() except Exception: pass else: value = self.make_bytes(value) content = self.make_bytes(value) # Create a list of properly encoded bytestrings to support write(). self._container = [value] self._container = [content] def __iter__(self): return iter(self._container) Loading
docs/ref/request-response.txt +7 −1 Original line number Diff line number Diff line Loading @@ -608,11 +608,17 @@ Passing iterators Finally, you can pass ``HttpResponse`` an iterator rather than strings. ``HttpResponse`` will consume the iterator immediately, store its content as a string, and discard it. string, and discard it. Objects with a ``close()`` method such as files and generators are immediately closed. If you need the response to be streamed from the iterator to the client, you must use the :class:`StreamingHttpResponse` class instead. .. versionchanged:: 1.10 Objects with a ``close()`` method used to be closed when the WSGI server called ``close()`` on the response. Setting header fields ~~~~~~~~~~~~~~~~~~~~~ Loading
docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -357,6 +357,10 @@ Miscellaneous * The ``add_postgis_srs()`` backwards compatibility alias for ``django.contrib.gis.utils.add_srs_entry()`` is removed. * Objects with a ``close()`` method such as files and generators passed to :class:`~django.http.HttpResponse` are now closed immediately instead of when the WSGI server calls ``close()`` on the response. .. _deprecated-features-1.10: Features deprecated in 1.10 Loading
tests/httpwrappers/tests.py +0 −13 Original line number Diff line number Diff line Loading @@ -588,18 +588,8 @@ class FileCloseTests(SimpleTestCase): # file isn't closed until we close the response. file1 = open(filename) r = HttpResponse(file1) self.assertFalse(file1.closed) r.close() self.assertTrue(file1.closed) # don't automatically close file when we finish iterating the response. file1 = open(filename) r = HttpResponse(file1) self.assertFalse(file1.closed) list(r) self.assertFalse(file1.closed) r.close() self.assertTrue(file1.closed) # when multiple file are assigned as content, make sure they are all # closed with the response. Loading @@ -607,9 +597,6 @@ class FileCloseTests(SimpleTestCase): file2 = open(filename) r = HttpResponse(file1) r.content = file2 self.assertFalse(file1.closed) self.assertFalse(file2.closed) r.close() self.assertTrue(file1.closed) self.assertTrue(file2.closed) Loading
tests/responses/tests.py +11 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ from __future__ import unicode_literals import io from django.conf import settings from django.core.cache import cache from django.http import HttpResponse from django.http.response import HttpResponseBase from django.test import SimpleTestCase Loading Loading @@ -121,3 +122,13 @@ class HttpResponseTests(SimpleTestCase): with io.TextIOWrapper(r, UTF8) as buf: buf.write(content) self.assertEqual(r.content, content.encode(UTF8)) def test_generator_cache(self): generator = ("{}".format(i) for i in range(10)) response = HttpResponse(content=generator) self.assertEqual(response.content, b'0123456789') self.assertRaises(StopIteration, next, generator) cache.set('my-response-key', response) response = cache.get('my-response-key') self.assertEqual(response.content, b'0123456789')