Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #13222 -- Made HttpResponse iterable once

response.content can be accessed many times as desired, and always
returns the same result.

iter(response) works only once and consumes the iterator.
  • Loading branch information...
commit 82b3e6ffcb9d810cc0e3ec27d25f89ce1fd525e0 1 parent 495a8b8
@aaugustin aaugustin authored
View
5 django/http/response.py
@@ -283,7 +283,8 @@ def __iter__(self):
'deprecated. Use `StreamingHttpResponse` instead '
'if you need the streaming behavior.',
PendingDeprecationWarning, stacklevel=2)
- self._iterator = iter(self._container)
+ if not hasattr(self, '_iterator'):
+ self._iterator = iter(self._container)
return self
def __next__(self):
@@ -303,7 +304,7 @@ def write(self, content):
def tell(self):
self._consume_content()
- return sum(len(chunk) for chunk in self)
+ return len(self.content)
class StreamingHttpResponse(HttpResponseBase):
View
6 django/test/testcases.py
@@ -596,7 +596,11 @@ def assertContains(self, response, text, count=None, status_code=200,
msg_prefix + "Couldn't retrieve content: Response code was %d"
" (expected %d)" % (response.status_code, status_code))
text = force_text(text, encoding=response._charset)
- content = b''.join(response).decode(response._charset)
+ if response.streaming:
+ content = b''.join(response.streaming_content)
+ else:
+ content = response.content
+ content = content.decode(response._charset)
# Avoid ResourceWarning about unclosed files.
response.close()
if html:
View
23 tests/regressiontests/httpwrappers/tests.py
@@ -337,15 +337,36 @@ def test_iter_content(self):
self.assertRaises(UnicodeEncodeError,
getattr, r, 'content')
- # content can safely be accessed multiple times.
+ # .content can safely be accessed multiple times.
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
+ self.assertEqual(b''.join(r), b'helloworld')
+ self.assertEqual(b''.join(r), b'')
+ # accessing .content still works
+ self.assertEqual(r.content, b'helloworld')
+
+ # XXX accessing .content doesn't work if the response was iterated first
+ # XXX change this when the deprecation completes in HttpResponse
+ r = HttpResponse(iter(['hello', 'world']))
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore", PendingDeprecationWarning)
+ self.assertEqual(b''.join(r), b'helloworld')
+ self.assertEqual(r.content, b'') # not the expected result!
# additional content can be written to the response.
+ r = HttpResponse(iter(['hello', 'world']))
+ self.assertEqual(r.content, b'helloworld')
r.write('!')
self.assertEqual(r.content, b'helloworld!')
+ def test_iterator_isnt_rewound(self):
+ # Regression test for #13222
+ r = HttpResponse('abc')
+ i = iter(r)
+ self.assertEqual(list(i), [b'abc'])
+ self.assertEqual(list(i), [])
def test_file_interface(self):
r = HttpResponse()
Please sign in to comment.
Something went wrong with that request. Please try again.