Commit a480f832 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

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.
parent 1124e163
Loading
Loading
Loading
Loading
+11 −13
Original line number Diff line number Diff line
@@ -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']
+3 −3
Original line number Diff line number Diff line
@@ -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.