summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2013-11-23 17:03:43 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2013-11-23 17:03:43 +0100
commita480f8320a5b36501bfd0e8cd70b8dc04adf2d08 (patch)
treea05240468a2567b090a1985255589a8fd6181f1c
parent1124e163403a1d474016cfc3cf9173eb44349e34 (diff)
Simplified iteration in HTTP response objects.
Fixed #20187 -- Allowed repeated iteration of HttpResponse. All this became possible when support for old-style streaming responses was finally removed.
-rw-r--r--django/http/response.py24
-rw-r--r--tests/httpwrappers/tests.py6
2 files changed, 14 insertions, 16 deletions
diff --git a/django/http/response.py b/django/http/response.py
index 532f8ee1e7..c590172a9c 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -282,13 +282,6 @@ class HttpResponseBase(six.Iterator):
# Handle non-string types (#16494)
return force_bytes(value, self._charset)
- def __iter__(self):
- return self
-
- def __next__(self):
- # Subclasses must define self._iterator for this function.
- return self.make_bytes(next(self._iterator))
-
# These methods partially implement the file-like object interface.
# See http://docs.python.org/lib/bltin-file-objects.html
@@ -337,23 +330,25 @@ class HttpResponse(HttpResponseBase):
@property
def content(self):
- return b''.join(self.make_bytes(e) for e in self._container)
+ return b''.join(self._container)
@content.setter
def content(self, value):
+ # Consume iterators upon assignment to allow repeated iteration.
if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)):
if hasattr(value, 'close'):
self._closable_objects.append(value)
- value = b''.join(self.make_bytes(e) for e in value)
+ value = b''.join(self.make_bytes(chunk) for chunk in value)
+ else:
+ value = self.make_bytes(value)
+ # Create a list of properly encoded bytestrings to support write().
self._container = [value]
def __iter__(self):
- if not hasattr(self, '_iterator'):
- self._iterator = iter(self._container)
- return self
+ return iter(self._container)
def write(self, content):
- self._container.append(content)
+ self._container.append(self.make_bytes(content))
def tell(self):
return len(self.content)
@@ -392,6 +387,9 @@ class StreamingHttpResponse(HttpResponseBase):
if hasattr(value, 'close'):
self._closable_objects.append(value)
+ def __iter__(self):
+ return self.streaming_content
+
class HttpResponseRedirectBase(HttpResponse):
allowed_schemes = ['http', 'https', 'ftp']
diff --git a/tests/httpwrappers/tests.py b/tests/httpwrappers/tests.py
index ccea20f9c5..06b29f89b9 100644
--- a/tests/httpwrappers/tests.py
+++ b/tests/httpwrappers/tests.py
@@ -356,10 +356,10 @@ class HttpResponseTests(unittest.TestCase):
r = HttpResponse(iter(['hello', 'world']))
self.assertEqual(r.content, r.content)
self.assertEqual(r.content, b'helloworld')
- # accessing the iterator works (once) after accessing .content
+ # __iter__ can safely be called multiple times (#20187).
self.assertEqual(b''.join(r), b'helloworld')
- self.assertEqual(b''.join(r), b'')
- # accessing .content still works
+ self.assertEqual(b''.join(r), b'helloworld')
+ # Accessing .content still works.
self.assertEqual(r.content, b'helloworld')
# Accessing .content also works if the response was iterated first.