]> git.ipfire.org Git - thirdparty/httpx.git/commitdiff
Make 'request' non-optional on responses (#666)
authorFlorimond Manca <florimond.manca@gmail.com>
Sat, 21 Dec 2019 14:38:25 +0000 (15:38 +0100)
committerGitHub <noreply@github.com>
Sat, 21 Dec 2019 14:38:25 +0000 (15:38 +0100)
* Make 'request' non-optional on Response

* Lint

* Remove remaining mention to null request

httpx/models.py
tests/dispatch/test_http2.py
tests/models/test_responses.py
tests/test_decoders.py
tests/test_multipart.py

index 93e6492fa62df0fdce513d9a0a44867db51fed7e..0a44d3258ee705161867bd6d721430fb906c147a 100644 (file)
@@ -661,11 +661,11 @@ class Response:
         self,
         status_code: int,
         *,
+        request: Request,
         http_version: str = None,
         headers: HeaderTypes = None,
         stream: ContentStream = None,
         content: bytes = None,
-        request: Request = None,
         history: typing.List["Response"] = None,
         elapsed: datetime.timedelta = None,
     ):
@@ -696,10 +696,8 @@ class Response:
     def url(self) -> typing.Optional[URL]:
         """
         Returns the URL for which the request was made.
-
-        Requires that `request` was provided when instantiating the response.
         """
-        return None if self.request is None else self.request.url
+        return self.request.url
 
     @property
     def content(self) -> bytes:
@@ -831,7 +829,6 @@ class Response:
     @property
     def cookies(self) -> "Cookies":
         if not hasattr(self, "_cookies"):
-            assert self.request is not None
             self._cookies = Cookies()
             self._cookies.extract_cookies(self)
         return self._cookies
@@ -967,7 +964,6 @@ class Cookies(MutableMapping):
         """
         Loads any cookies based on the response `Set-Cookie` headers.
         """
-        assert response.request is not None
         urlib_response = self._CookieCompatResponse(response)
         urllib_request = self._CookieCompatRequest(response.request)
 
index e1580045e0b67a4d3bb657e0ddd9f755054c8e92..0efca5fa4ac27598ac03be334ccd15414dd4f8f2 100644 (file)
@@ -19,7 +19,7 @@ async def app(request):
         {"method": method, "path": path, "body": body.decode()}
     ).encode()
     headers = {"Content-Length": str(len(content))}
-    return Response(200, headers=headers, content=content)
+    return Response(200, headers=headers, content=content, request=request)
 
 
 @pytest.mark.asyncio
index 7b0281b08507db426a0d4fe01372a1be72012bb2..3133e03dd48cc91e49791e76c9d84617a962619d 100644 (file)
@@ -7,6 +7,8 @@ import pytest
 import httpx
 from httpx.content_streams import AsyncIteratorStream
 
+REQUEST = httpx.Request("GET", "https://example.org")
+
 
 def streaming_body():
     yield b"Hello, "
@@ -19,16 +21,17 @@ async def async_streaming_body():
 
 
 def test_response():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
     assert response.text == "Hello, world!"
+    assert response.request is REQUEST
     assert response.elapsed == datetime.timedelta(0)
     assert not response.is_error
 
 
 def test_response_repr():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
     assert repr(response) == "<Response [200 OK]>"
 
 
@@ -38,7 +41,7 @@ def test_response_content_type_encoding():
     """
     headers = {"Content-Type": "text-plain; charset=latin-1"}
     content = "Latin 1: ÿ".encode("latin-1")
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.text == "Latin 1: ÿ"
     assert response.encoding == "latin-1"
 
@@ -48,7 +51,7 @@ def test_response_autodetect_encoding():
     Autodetect encoding if there is no charset info in a Content-Type header.
     """
     content = "おはようございます。".encode("EUC-JP")
-    response = httpx.Response(200, content=content)
+    response = httpx.Response(200, content=content, request=REQUEST)
     assert response.text == "おはようございます。"
     assert response.encoding == "EUC-JP"
 
@@ -59,7 +62,7 @@ def test_response_fallback_to_autodetect():
     """
     headers = {"Content-Type": "text-plain; charset=invalid-codec-name"}
     content = "おはようございます。".encode("EUC-JP")
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.text == "おはようございます。"
     assert response.encoding == "EUC-JP"
 
@@ -71,7 +74,7 @@ def test_response_default_text_encoding():
     """
     content = b"Hello, world!"
     headers = {"Content-Type": "text/plain"}
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.status_code == 200
     assert response.encoding == "iso-8859-1"
     assert response.text == "Hello, world!"
@@ -81,7 +84,7 @@ def test_response_default_encoding():
     """
     Default to utf-8 if all else fails.
     """
-    response = httpx.Response(200, content=b"")
+    response = httpx.Response(200, content=b"", request=REQUEST)
     assert response.text == ""
     assert response.encoding == "utf-8"
 
@@ -91,7 +94,7 @@ def test_response_non_text_encoding():
     Default to apparent encoding for non-text content-type headers.
     """
     headers = {"Content-Type": "image/png"}
-    response = httpx.Response(200, content=b"xyz", headers=headers)
+    response = httpx.Response(200, content=b"xyz", headers=headers, request=REQUEST)
     assert response.text == "xyz"
     assert response.encoding == "ascii"
 
@@ -101,7 +104,7 @@ def test_response_set_explicit_encoding():
         "Content-Type": "text-plain; charset=utf-8"
     }  # Deliberately incorrect charset
     response = httpx.Response(
-        200, content="Latin 1: ÿ".encode("latin-1"), headers=headers
+        200, content="Latin 1: ÿ".encode("latin-1"), headers=headers, request=REQUEST,
     )
     response.encoding = "latin-1"
     assert response.text == "Latin 1: ÿ"
@@ -109,7 +112,9 @@ def test_response_set_explicit_encoding():
 
 
 def test_response_force_encoding():
-    response = httpx.Response(200, content="Snowman: ☃".encode("utf-8"))
+    response = httpx.Response(
+        200, content="Snowman: ☃".encode("utf-8"), request=REQUEST
+    )
     response.encoding = "iso-8859-1"
     assert response.status_code == 200
     assert response.reason_phrase == "OK"
@@ -119,7 +124,7 @@ def test_response_force_encoding():
 
 @pytest.mark.asyncio
 async def test_read_response():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
 
     assert response.status_code == 200
     assert response.text == "Hello, world!"
@@ -135,7 +140,7 @@ async def test_read_response():
 
 @pytest.mark.asyncio
 async def test_raw_interface():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
 
     raw = b""
     async for part in response.aiter_raw():
@@ -145,7 +150,7 @@ async def test_raw_interface():
 
 @pytest.mark.asyncio
 async def test_bytes_interface():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
 
     content = b""
     async for part in response.aiter_bytes():
@@ -155,7 +160,7 @@ async def test_bytes_interface():
 
 @pytest.mark.asyncio
 async def test_text_interface():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
 
     await response.read()
 
@@ -167,7 +172,7 @@ async def test_text_interface():
 
 @pytest.mark.asyncio
 async def test_lines_interface():
-    response = httpx.Response(200, content=b"Hello,\nworld!")
+    response = httpx.Response(200, content=b"Hello,\nworld!", request=REQUEST)
 
     await response.read()
 
@@ -179,7 +184,7 @@ async def test_lines_interface():
 
 @pytest.mark.asyncio
 async def test_stream_interface_after_read():
-    response = httpx.Response(200, content=b"Hello, world!")
+    response = httpx.Response(200, content=b"Hello, world!", request=REQUEST)
 
     await response.read()
 
@@ -192,7 +197,7 @@ async def test_stream_interface_after_read():
 @pytest.mark.asyncio
 async def test_streaming_response():
     stream = AsyncIteratorStream(aiterator=async_streaming_body())
-    response = httpx.Response(200, stream=stream)
+    response = httpx.Response(200, stream=stream, request=REQUEST)
 
     assert response.status_code == 200
     assert not response.is_closed
@@ -207,7 +212,7 @@ async def test_streaming_response():
 @pytest.mark.asyncio
 async def test_cannot_read_after_stream_consumed():
     stream = AsyncIteratorStream(aiterator=async_streaming_body())
-    response = httpx.Response(200, stream=stream)
+    response = httpx.Response(200, stream=stream, request=REQUEST)
 
     content = b""
     async for part in response.aiter_bytes():
@@ -220,7 +225,7 @@ async def test_cannot_read_after_stream_consumed():
 @pytest.mark.asyncio
 async def test_cannot_read_after_response_closed():
     stream = AsyncIteratorStream(aiterator=async_streaming_body())
-    response = httpx.Response(200, stream=stream)
+    response = httpx.Response(200, stream=stream, request=REQUEST)
 
     await response.close()
 
@@ -229,7 +234,7 @@ async def test_cannot_read_after_response_closed():
 
 
 def test_unknown_status_code():
-    response = httpx.Response(600)
+    response = httpx.Response(600, request=REQUEST)
     assert response.status_code == 600
     assert response.reason_phrase == ""
     assert response.text == ""
@@ -239,7 +244,7 @@ def test_json_with_specified_encoding():
     data = {"greeting": "hello", "recipient": "world"}
     content = json.dumps(data).encode("utf-16")
     headers = {"Content-Type": "application/json, charset=utf-16"}
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.json() == data
 
 
@@ -247,7 +252,7 @@ def test_json_with_options():
     data = {"greeting": "hello", "recipient": "world", "amount": 1}
     content = json.dumps(data).encode("utf-16")
     headers = {"Content-Type": "application/json, charset=utf-16"}
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.json(parse_int=str)["amount"] == "1"
 
 
@@ -255,7 +260,7 @@ def test_json_without_specified_encoding():
     data = {"greeting": "hello", "recipient": "world"}
     content = json.dumps(data).encode("utf-32-be")
     headers = {"Content-Type": "application/json"}
-    response = httpx.Response(200, content=content, headers=headers)
+    response = httpx.Response(200, content=content, headers=headers, request=REQUEST)
     assert response.json() == data
 
 
@@ -265,7 +270,9 @@ def test_json_without_specified_encoding_decode_error():
     headers = {"Content-Type": "application/json"}
     # force incorrect guess from `guess_json_utf` to trigger error
     with mock.patch("httpx.models.guess_json_utf", return_value="utf-32"):
-        response = httpx.Response(200, content=content, headers=headers)
+        response = httpx.Response(
+            200, content=content, headers=headers, request=REQUEST
+        )
         with pytest.raises(json.JSONDecodeError):
             response.json()
 
@@ -287,5 +294,5 @@ def test_json_without_specified_encoding_decode_error():
     ],
 )
 def test_link_headers(headers, expected):
-    response = httpx.Response(200, content=None, headers=headers)
+    response = httpx.Response(200, content=None, headers=headers, request=REQUEST)
     assert response.links == expected
index feea42e5e3e727390a823a74cf65b747d68f74de..307ab5b23e14020e42f9d26e25cce45fbd189dbc 100644 (file)
@@ -14,6 +14,8 @@ from httpx.decoders import (
     TextDecoder,
 )
 
+REQUEST = httpx.Request("GET", "https://example.org")
+
 
 def test_deflate():
     body = b"test 123"
@@ -21,7 +23,9 @@ def test_deflate():
     compressed_body = compressor.compress(body) + compressor.flush()
 
     headers = [(b"Content-Encoding", b"deflate")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
 
@@ -31,7 +35,9 @@ def test_gzip():
     compressed_body = compressor.compress(body) + compressor.flush()
 
     headers = [(b"Content-Encoding", b"gzip")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
 
@@ -40,7 +46,9 @@ def test_brotli():
     compressed_body = brotli.compress(body)
 
     headers = [(b"Content-Encoding", b"br")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
 
@@ -56,7 +64,9 @@ def test_multi():
     )
 
     headers = [(b"Content-Encoding", b"deflate, gzip")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
 
@@ -65,11 +75,15 @@ def test_multi_with_identity():
     compressed_body = brotli.compress(body)
 
     headers = [(b"Content-Encoding", b"br, identity")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
     headers = [(b"Content-Encoding", b"identity, br")]
-    response = httpx.Response(200, headers=headers, content=compressed_body)
+    response = httpx.Response(
+        200, headers=headers, content=compressed_body, request=REQUEST
+    )
     assert response.content == body
 
 
@@ -84,7 +98,7 @@ async def test_streaming():
 
     headers = [(b"Content-Encoding", b"gzip")]
     stream = AsyncIteratorStream(aiterator=compress(body))
-    response = httpx.Response(200, headers=headers, stream=stream)
+    response = httpx.Response(200, headers=headers, stream=stream, request=REQUEST)
     assert not hasattr(response, "body")
     assert await response.read() == body
 
@@ -92,7 +106,7 @@ async def test_streaming():
 @pytest.mark.parametrize("header_value", (b"deflate", b"gzip", b"br", b"identity"))
 def test_empty_content(header_value):
     headers = [(b"Content-Encoding", header_value)]
-    response = httpx.Response(200, headers=headers, content=b"")
+    response = httpx.Response(200, headers=headers, content=b"", request=REQUEST)
     assert response.content == b""
 
 
@@ -111,7 +125,9 @@ def test_decoding_errors(header_value):
     body = b"test 123"
     compressed_body = brotli.compress(body)[3:]
     with pytest.raises(httpx.DecodingError):
-        response = httpx.Response(200, headers=headers, content=compressed_body)
+        response = httpx.Response(
+            200, headers=headers, content=compressed_body, request=REQUEST
+        )
         response.content
 
 
@@ -140,7 +156,7 @@ async def test_text_decoder(data, encoding):
             yield chunk
 
     stream = AsyncIteratorStream(aiterator=iterator())
-    response = httpx.Response(200, stream=stream)
+    response = httpx.Response(200, stream=stream, request=REQUEST)
     await response.read()
     assert response.text == (b"".join(data)).decode(encoding)
 
@@ -157,6 +173,7 @@ async def test_text_decoder_known_encoding():
         200,
         headers=[(b"Content-Type", b"text/html; charset=shift-jis")],
         stream=stream,
+        request=REQUEST,
     )
 
     await response.read()
@@ -218,5 +235,5 @@ def test_invalid_content_encoding_header():
     headers = [(b"Content-Encoding", b"invalid-header")]
     body = b"test 123"
 
-    response = httpx.Response(200, headers=headers, content=body)
+    response = httpx.Response(200, headers=headers, content=body, request=REQUEST)
     assert response.content == body
index a47a7b31d81bcc9b5d0123b75b4d9f930f1c830b..fb7618cb60255f1bd22e1f0d13c908989627d092 100644 (file)
@@ -22,7 +22,7 @@ class MockDispatch(Dispatcher):
         timeout: TimeoutTypes = None,
     ) -> httpx.Response:
         content = b"".join([part async for part in request.stream])
-        return httpx.Response(200, content=content)
+        return httpx.Response(200, content=content, request=request)
 
 
 @pytest.mark.parametrize(("value,output"), (("abc", b"abc"), (b"abc", b"abc")))