Repository: encode/httpx
Pull request #599 (2019-12-05 11:23:30)

Consistent suite of `stream_*` methods
Renames `.raw()` to `.stream_raw()`, and renames `.stream()` to `.stream_bytes()`, so that we have a nice consistent suite of streaming operations...

* `response.stream_raw()`
* `response.stream_bytes)`
* `response.stream_text()`
* `response.stream_lines()`

Plus also...

* `response.read()`, `response.close()`

The existing `.raw` and `.stream` methods remain for compat, but issue warnings.

This is the first part of #588

We don't yet have any streaming docs. We might want to wait until we also address the second part of this work, and add the documentation as part of *that* pull request rather than *this* one, since we've got some new API that we want to add there.


Patch:
diff --git a/docs/api.md b/docs/api.md
index b4e5670..2dff987 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -63,8 +63,10 @@
 * `def .raise_for_status()` - **None**
 * `def .json()` - **Any**
 * `def .read()` - **bytes**
-* `def .stream()` - **bytes iterator**
-* `def .raw()` - **bytes iterator**
+* `def .stream_raw()` - **async bytes iterator**
+* `def .stream_bytes()` - **async bytes iterator**
+* `def .stream_text()` - **async text iterator**
+* `def .stream_lines()` - **async text iterator**
 * `def .close()` - **None**
 * `def .next()` - **Response**
 
diff --git a/httpx/models.py b/httpx/models.py
index d702903..0d7c6fc 100644
--- a/httpx/models.py
+++ b/httpx/models.py
@@ -4,6 +4,7 @@ import email.message
 import json as jsonlib
 import typing
 import urllib.request
+import warnings
 from collections.abc import MutableMapping
 from http.cookiejar import Cookie, CookieJar
 from urllib.parse import parse_qsl, urlencode
@@ -701,7 +702,7 @@ class Request:
 
     async def read(self) -> bytes:
         """
-        Read and return the response content.
+        Read and return the request content.
         """
         if not hasattr(self, "content"):
             self.content = b"".join([part async for part in self.stream()])
@@ -918,10 +919,26 @@ class Response:
         Read and return the response content.
         """
         if not hasattr(self, "_content"):
-            self._content = b"".join([part async for part in self.stream()])
+            self._content = b"".join([part async for part in self.stream_bytes()])
         return self._content
 
-    async def stream(self) -> typing.AsyncIterator[bytes]:
+    @property
+    def stream(self):  # type: ignore
+        warnings.warn(
+            "Response.stream() is due to be deprecated. "
+            "Use Response.stream_bytes() instead."
+        )
+        return self.stream_bytes
+
+    @property
+    def raw(self):  # type: ignore
+        warnings.warn(
+            "Response.raw() is due to be deprecated. "
+            "Use Response.stream_raw() instead."
+        )
+        return self.stream_raw
+
+    async def stream_bytes(self) -> typing.AsyncIterator[bytes]:
         """
         A byte-iterator over the decoded response content.
         This allows us to handle gzip, deflate, and brotli encoded responses.
@@ -929,7 +946,7 @@ class Response:
         if hasattr(self, "_content"):
             yield self._content
         else:
-            async for chunk in self.raw():
+            async for chunk in self.stream_raw():
                 yield self.decoder.decode(chunk)
             yield self.decoder.flush()
 
@@ -940,7 +957,7 @@ class Response:
         string encoding.
         """
         decoder = TextDecoder(encoding=self.charset_encoding)
-        async for chunk in self.stream():
+        async for chunk in self.stream_bytes():
             yield decoder.decode(chunk)
         yield decoder.flush()
 
@@ -952,7 +969,7 @@ class Response:
         for line in decoder.flush():
             yield line
 
-    async def raw(self) -> typing.AsyncIterator[bytes]:
+    async def stream_raw(self) -> typing.AsyncIterator[bytes]:
         """
         A byte-iterator over the raw response content.
         """


Test patch:
diff --git a/tests/client/test_client.py b/tests/client/test_client.py
index 5514f6d..668ae30 100644
--- a/tests/client/test_client.py
+++ b/tests/client/test_client.py
@@ -71,7 +71,7 @@ async def test_stream_iterator(server):
         response = await client.get(server.url, stream=True)
     assert response.status_code == 200
     body = b""
-    async for chunk in response.stream():
+    async for chunk in response.stream_bytes():
         body += chunk
     assert body == b"Hello, world!"
 
@@ -82,7 +82,7 @@ async def test_raw_iterator(server):
         response = await client.get(server.url, stream=True)
     assert response.status_code == 200
     body = b""
-    async for chunk in response.raw():
+    async for chunk in response.stream_raw():
         body += chunk
     assert body == b"Hello, world!"
     await response.close()
diff --git a/tests/models/test_responses.py b/tests/models/test_responses.py
index 9b60c67..1e1fb89 100644
--- a/tests/models/test_responses.py
+++ b/tests/models/test_responses.py
@@ -137,7 +137,7 @@ async def test_raw_interface():
     response = httpx.Response(200, content=b"Hello, world!")
 
     raw = b""
-    async for part in response.raw():
+    async for part in response.stream_raw():
         raw += part
     assert raw == b"Hello, world!"
 
@@ -147,7 +147,7 @@ async def test_stream_interface():
     response = httpx.Response(200, content=b"Hello, world!")
 
     content = b""
-    async for part in response.stream():
+    async for part in response.stream_bytes():
         content += part
     assert content == b"Hello, world!"
 
@@ -183,7 +183,7 @@ async def test_stream_interface_after_read():
     await response.read()
 
     content = b""
-    async for part in response.stream():
+    async for part in response.stream_bytes():
         content += part
     assert content == b"Hello, world!"
 
@@ -207,7 +207,7 @@ async def test_cannot_read_after_stream_consumed():
     response = httpx.Response(200, content=async_streaming_body())
 
     content = b""
-    async for part in response.stream():
+    async for part in response.stream_bytes():
         content += part
 
     with pytest.raises(httpx.StreamConsumed):