From: Kar Petrosyan Date: Thu, 27 Feb 2025 16:47:41 +0000 (+0400) Subject: fix unasync X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7668b6ea021d1c98092930a0e5c436b105d4c81;p=thirdparty%2Fhttpx.git fix unasync --- diff --git a/tests/client/sync/test_auth.py b/tests/client/sync/test_auth.py index 8aa1671c..d49f3384 100644 --- a/tests/client/sync/test_auth.py +++ b/tests/client/sync/test_auth.py @@ -9,10 +9,10 @@ import netrc import os import sys import typing -from threading import Lock from urllib.request import parse_keqv_list import pytest +from threading import Lock import httpx @@ -148,6 +148,7 @@ class Auth(httpx.Auth): yield request + def test_basic_auth() -> None: url = "https://example.org/" auth = ("user", "password123") @@ -160,6 +161,7 @@ def test_basic_auth() -> None: assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="} + def test_basic_auth_with_stream() -> None: """ See: https://github.com/encode/httpx/pull/1312 @@ -168,7 +170,9 @@ def test_basic_auth_with_stream() -> None: auth = ("user", "password123") app = App() - with httpx.Client(transport=httpx.MockTransport(app), auth=auth) as client: + with httpx.Client( + transport=httpx.MockTransport(app), auth=auth + ) as client: with client.stream("GET", url) as response: response.read() @@ -176,6 +180,7 @@ def test_basic_auth_with_stream() -> None: assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="} + def test_basic_auth_in_url() -> None: url = "https://user:password123@example.org/" app = App() @@ -187,18 +192,22 @@ def test_basic_auth_in_url() -> None: assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="} + def test_basic_auth_on_session() -> None: url = "https://example.org/" auth = ("user", "password123") app = App() - with httpx.Client(transport=httpx.MockTransport(app), auth=auth) as client: + with httpx.Client( + transport=httpx.MockTransport(app), auth=auth + ) as client: response = client.get(url) assert response.status_code == 200 assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="} + def test_custom_auth() -> None: url = "https://example.org/" app = App() @@ -214,6 +223,7 @@ def test_custom_auth() -> None: assert response.json() == {"auth": "Token 123"} + def test_netrc_auth_credentials_exist() -> None: """ When netrc auth is being used and a request is made to a host that is @@ -224,7 +234,9 @@ def test_netrc_auth_credentials_exist() -> None: app = App() auth = httpx.NetRCAuth(netrc_file) - with httpx.Client(transport=httpx.MockTransport(app), auth=auth) as client: + with httpx.Client( + transport=httpx.MockTransport(app), auth=auth + ) as client: response = client.get(url) assert response.status_code == 200 @@ -233,6 +245,7 @@ def test_netrc_auth_credentials_exist() -> None: } + def test_netrc_auth_credentials_do_not_exist() -> None: """ When netrc auth is being used and a request is made to a host that is @@ -243,7 +256,9 @@ def test_netrc_auth_credentials_do_not_exist() -> None: app = App() auth = httpx.NetRCAuth(netrc_file) - with httpx.Client(transport=httpx.MockTransport(app), auth=auth) as client: + with httpx.Client( + transport=httpx.MockTransport(app), auth=auth + ) as client: response = client.get(url) assert response.status_code == 200 @@ -254,6 +269,7 @@ def test_netrc_auth_credentials_do_not_exist() -> None: sys.version_info >= (3, 11), reason="netrc files without a password are valid from Python >= 3.11", ) + def test_netrc_auth_nopassword_parse_error() -> None: # pragma: no cover """ Python has different netrc parsing behaviours with different versions. @@ -265,18 +281,22 @@ def test_netrc_auth_nopassword_parse_error() -> None: # pragma: no cover httpx.NetRCAuth(netrc_file) + def test_auth_disable_per_request() -> None: url = "https://example.org/" auth = ("user", "password123") app = App() - with httpx.Client(transport=httpx.MockTransport(app), auth=auth) as client: + with httpx.Client( + transport=httpx.MockTransport(app), auth=auth + ) as client: response = client.get(url, auth=None) assert response.status_code == 200 assert response.json() == {"auth": None} + def test_auth_hidden_url() -> None: url = "http://example-username:example-password@example.org/" expected = "URL('http://example-username:[secure]@example.org/')" @@ -284,6 +304,7 @@ def test_auth_hidden_url() -> None: assert expected == repr(httpx.URL(url)) + def test_auth_hidden_header() -> None: url = "https://example.org/" auth = ("example-username", "example-password") @@ -295,6 +316,7 @@ def test_auth_hidden_header() -> None: assert "'authorization': '[secure]'" in str(response.request.headers) + def test_auth_property() -> None: app = App() @@ -310,6 +332,7 @@ def test_auth_property() -> None: assert response.json() == {"auth": "Basic dXNlcjpwYXNzd29yZDEyMw=="} + def test_auth_invalid_type() -> None: app = App() @@ -327,6 +350,7 @@ def test_auth_invalid_type() -> None: client.auth = "not a tuple, not a callable" # type: ignore + def test_digest_auth_returns_no_auth_if_no_digest_header_in_response() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -340,6 +364,7 @@ def test_digest_auth_returns_no_auth_if_no_digest_header_in_response() -> None: assert len(response.history) == 0 + def test_digest_auth_returns_no_auth_if_alternate_auth_scheme() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -354,6 +379,7 @@ def test_digest_auth_returns_no_auth_if_alternate_auth_scheme() -> None: assert len(response.history) == 0 + def test_digest_auth_200_response_including_digest_auth_header() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -368,6 +394,7 @@ def test_digest_auth_200_response_including_digest_auth_header() -> None: assert len(response.history) == 0 + def test_digest_auth_401_response_without_digest_auth_header() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -394,6 +421,7 @@ def test_digest_auth_401_response_without_digest_auth_header() -> None: ("SHA-512-SESS", 64, 128), ], ) + def test_digest_auth( algorithm: str, expected_hash_length: int, expected_response_length: int ) -> None: @@ -426,6 +454,7 @@ def test_digest_auth( assert len(digest_data["cnonce"]) == 16 + 2 + def test_digest_auth_no_specified_qop() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -457,6 +486,7 @@ def test_digest_auth_no_specified_qop() -> None: @pytest.mark.parametrize("qop", ("auth, auth-int", "auth,auth-int", "unknown,auth")) + def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str) -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -469,6 +499,7 @@ def test_digest_auth_qop_including_spaces_and_auth_returns_auth(qop: str) -> Non assert len(response.history) == 1 + def test_digest_auth_qop_auth_int_not_implemented() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -479,6 +510,7 @@ def test_digest_auth_qop_auth_int_not_implemented() -> None: client.get(url, auth=auth) + def test_digest_auth_qop_must_be_auth_or_auth_int() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -489,6 +521,7 @@ def test_digest_auth_qop_must_be_auth_or_auth_int() -> None: client.get(url, auth=auth) + def test_digest_auth_incorrect_credentials() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -501,6 +534,7 @@ def test_digest_auth_incorrect_credentials() -> None: assert len(response.history) == 1 + def test_digest_auth_reuses_challenge() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -517,6 +551,7 @@ def test_digest_auth_reuses_challenge() -> None: assert len(response_2.history) == 0 + def test_digest_auth_resets_nonce_count_after_401() -> None: url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -563,6 +598,7 @@ def test_digest_auth_resets_nonce_count_after_401() -> None: 'Digest realm="httpx@example.org", qop="auth,au', # malformed fields list ], ) + def test_digest_auth_raises_protocol_error_on_malformed_header( auth_header: str, ) -> None: @@ -575,6 +611,7 @@ def test_digest_auth_raises_protocol_error_on_malformed_header( client.get(url, auth=auth) + def test_auth_history() -> None: """ Test that intermediate requests sent as part of an authentication flow @@ -609,6 +646,7 @@ class ConsumeBodyTransport(httpx.MockTransport): return self.handler(request) # type: ignore[return-value] + def test_digest_auth_unavailable_streaming_body(): url = "https://example.org/" auth = httpx.DigestAuth(username="user", password="password123") @@ -622,6 +660,7 @@ def test_digest_auth_unavailable_streaming_body(): client.post(url, content=streaming_body(), auth=auth) + def test_auth_reads_response_body() -> None: """ Test that we can read the response body in an auth flow if `requires_response_body` @@ -638,6 +677,7 @@ def test_auth_reads_response_body() -> None: assert response.json() == {"auth": '{"auth":"xyz"}'} + def test_auth() -> None: """ Test that we can use an auth implementation specific to the async case, to diff --git a/tests/client/sync/test_client.py b/tests/client/sync/test_client.py index fc267ad1..b648cdcf 100644 --- a/tests/client/sync/test_client.py +++ b/tests/client/sync/test_client.py @@ -8,6 +8,7 @@ import pytest import httpx + def test_get(server): url = server.url with httpx.Client(http2=True) as client: @@ -28,12 +29,14 @@ def test_get(server): pytest.param("http://", id="no-host"), ], ) + def test_get_invalid_url(server, url): with httpx.Client() as client: with pytest.raises((httpx.UnsupportedProtocol, httpx.LocalProtocolError)): client.get(url) + def test_build_request(server): url = server.url.copy_with(path="/echo_headers") headers = {"Custom-header": "value"} @@ -48,6 +51,7 @@ def test_build_request(server): assert response.json()["Custom-header"] == "value" + def test_post(server): url = server.url with httpx.Client() as client: @@ -55,6 +59,7 @@ def test_post(server): assert response.status_code == 200 + def test_post_json(server): url = server.url with httpx.Client() as client: @@ -62,6 +67,7 @@ def test_post_json(server): assert response.status_code == 200 + def test_stream_response(server): with httpx.Client() as client: with client.stream("GET", server.url) as response: @@ -72,6 +78,7 @@ def test_stream_response(server): assert response.content == b"Hello, world!" + def test_access_content_stream_response(server): with httpx.Client() as client: with client.stream("GET", server.url) as response: @@ -82,6 +89,7 @@ def test_access_content_stream_response(server): response.content # noqa: B018 + def test_stream_request(server): def hello_world() -> typing.Iterator[bytes]: yield b"Hello, " @@ -92,6 +100,7 @@ def test_stream_request(server): assert response.status_code == 200 + def test_raise_for_status(server): with httpx.Client() as client: for status_code in (200, 400, 404, 500, 505): @@ -107,6 +116,7 @@ def test_raise_for_status(server): assert response.raise_for_status() is response + def test_options(server): with httpx.Client() as client: response = client.options(server.url) @@ -114,6 +124,7 @@ def test_options(server): assert response.text == "Hello, world!" + def test_head(server): with httpx.Client() as client: response = client.head(server.url) @@ -121,18 +132,21 @@ def test_head(server): assert response.text == "" + def test_put(server): with httpx.Client() as client: response = client.put(server.url, content=b"Hello, world!") assert response.status_code == 200 + def test_patch(server): with httpx.Client() as client: response = client.patch(server.url, content=b"Hello, world!") assert response.status_code == 200 + def test_delete(server): with httpx.Client() as client: response = client.delete(server.url) @@ -140,6 +154,7 @@ def test_delete(server): assert response.text == "Hello, world!" + def test_100_continue(server): headers = {"Expect": "100-continue"} content = b"Echo request body" @@ -153,6 +168,7 @@ def test_100_continue(server): assert response.content == content + def test_context_managed_transport(): class Transport(httpx.BaseTransport): def __init__(self) -> None: @@ -184,6 +200,7 @@ def test_context_managed_transport(): ] + def test_context_managed_transport_and_mount(): class Transport(httpx.BaseTransport): def __init__(self, name: str) -> None: @@ -207,7 +224,9 @@ def test_context_managed_transport_and_mount(): transport = Transport(name="transport") mounted = Transport(name="mounted") - with httpx.Client(transport=transport, mounts={"http://www.example.org": mounted}): + with httpx.Client( + transport=transport, mounts={"http://www.example.org": mounted} + ): pass assert transport.events == [ @@ -226,6 +245,7 @@ def hello_world(request): return httpx.Response(200, text="Hello, world!") + def test_client_closed_state_using_implicit_open(): client = httpx.Client(transport=httpx.MockTransport(hello_world)) @@ -246,6 +266,7 @@ def test_client_closed_state_using_implicit_open(): pass # pragma: no cover + def test_client_closed_state_using_with_block(): with httpx.Client(transport=httpx.MockTransport(hello_world)) as client: assert not client.is_closed @@ -266,6 +287,7 @@ def mounted(request: httpx.Request) -> httpx.Response: return httpx.Response(200, json=data) + def test_mounted_transport(): transport = httpx.MockTransport(unmounted) mounts = {"custom://": httpx.MockTransport(mounted)} @@ -280,6 +302,7 @@ def test_mounted_transport(): assert response.json() == {"app": "mounted"} + def test_mock_transport(): def hello_world(request: httpx.Request) -> httpx.Response: return httpx.Response(200, text="Hello, world!") @@ -292,6 +315,7 @@ def test_mock_transport(): assert response.text == "Hello, world!" + def test_cancellation_during_stream(): """ If any BaseException is raised during streaming the response, then the @@ -331,6 +355,7 @@ def test_cancellation_during_stream(): assert stream_was_closed + def test_server_extensions(server): url = server.url with httpx.Client(http2=True) as client: diff --git a/tests/client/sync/test_cookies.py b/tests/client/sync/test_cookies.py index 35452b3e..4fccf265 100644 --- a/tests/client/sync/test_cookies.py +++ b/tests/client/sync/test_cookies.py @@ -15,6 +15,7 @@ def get_and_set_cookies(request: httpx.Request) -> httpx.Response: raise NotImplementedError() # pragma: no cover + def test_set_cookie() -> None: """ Send a request including a cookie. @@ -31,6 +32,7 @@ def test_set_cookie() -> None: assert response.json() == {"cookies": "example-name=example-value"} + def test_set_per_request_cookie_is_deprecated() -> None: """ Sending a request including a per-request cookie is deprecated. @@ -38,7 +40,9 @@ def test_set_per_request_cookie_is_deprecated() -> None: url = "http://example.org/echo_cookies" cookies = {"example-name": "example-value"} - with httpx.Client(transport=httpx.MockTransport(get_and_set_cookies)) as client: + with httpx.Client( + transport=httpx.MockTransport(get_and_set_cookies) + ) as client: with pytest.warns(DeprecationWarning): response = client.get(url, cookies=cookies) @@ -46,6 +50,7 @@ def test_set_per_request_cookie_is_deprecated() -> None: assert response.json() == {"cookies": "example-name=example-value"} + def test_set_cookie_with_cookiejar() -> None: """ Send a request including a cookie, using a `CookieJar` instance. @@ -83,6 +88,7 @@ def test_set_cookie_with_cookiejar() -> None: assert response.json() == {"cookies": "example-name=example-value"} + def test_setting_client_cookies_to_cookiejar() -> None: """ Send a request including a cookie, using a `CookieJar` instance. @@ -120,6 +126,7 @@ def test_setting_client_cookies_to_cookiejar() -> None: assert response.json() == {"cookies": "example-name=example-value"} + def test_set_cookie_with_cookies_model() -> None: """ Send a request including a cookie, using a `Cookies` instance. @@ -129,7 +136,9 @@ def test_set_cookie_with_cookies_model() -> None: cookies = httpx.Cookies() cookies["example-name"] = "example-value" - with httpx.Client(transport=httpx.MockTransport(get_and_set_cookies)) as client: + with httpx.Client( + transport=httpx.MockTransport(get_and_set_cookies) + ) as client: client.cookies = cookies response = client.get(url) @@ -137,10 +146,13 @@ def test_set_cookie_with_cookies_model() -> None: assert response.json() == {"cookies": "example-name=example-value"} + def test_get_cookie() -> None: url = "http://example.org/set_cookie" - with httpx.Client(transport=httpx.MockTransport(get_and_set_cookies)) as client: + with httpx.Client( + transport=httpx.MockTransport(get_and_set_cookies) + ) as client: response = client.get(url) assert response.status_code == 200 @@ -148,11 +160,14 @@ def test_get_cookie() -> None: assert client.cookies["example-name"] == "example-value" + def test_cookie_persistence() -> None: """ Ensure that Client instances persist cookies between requests. """ - with httpx.Client(transport=httpx.MockTransport(get_and_set_cookies)) as client: + with httpx.Client( + transport=httpx.MockTransport(get_and_set_cookies) + ) as client: response = client.get("http://example.org/echo_cookies") assert response.status_code == 200 assert response.json() == {"cookies": None} diff --git a/tests/client/sync/test_event_hooks.py b/tests/client/sync/test_event_hooks.py index df96199e..6a5e6745 100644 --- a/tests/client/sync/test_event_hooks.py +++ b/tests/client/sync/test_event_hooks.py @@ -1,3 +1,5 @@ +import pytest + import httpx @@ -11,6 +13,7 @@ def app(request: httpx.Request) -> httpx.Response: return httpx.Response(200, headers={"server": "testserver"}) + def test_event_hooks(): events = [] @@ -46,6 +49,7 @@ def test_event_hooks(): ] + def test_event_hooks_raising_exception(): def raise_on_4xx_5xx(response): response.raise_for_status() @@ -61,6 +65,7 @@ def test_event_hooks_raising_exception(): assert exc.response.is_closed + def test_event_hooks_with_redirect(): """ A redirect request should trigger additional 'request' and 'response' event hooks. diff --git a/tests/client/sync/test_headers.py b/tests/client/sync/test_headers.py index a9e296ad..6d640fc6 100644 --- a/tests/client/sync/test_headers.py +++ b/tests/client/sync/test_headers.py @@ -20,6 +20,7 @@ def echo_repeated_headers_items(request: httpx.Request) -> httpx.Response: return httpx.Response(200, json=data) + def test_client_header(): """ Set a header in the Client. @@ -45,6 +46,7 @@ def test_client_header(): } + def test_header_merge(): url = "http://example.org/echo_headers" client_headers = {"User-Agent": "python-myclient/0.2.1"} @@ -67,6 +69,7 @@ def test_header_merge(): } + def test_header_merge_conflicting_headers(): url = "http://example.org/echo_headers" client_headers = {"X-Auth-Token": "FooBar"} @@ -89,6 +92,7 @@ def test_header_merge_conflicting_headers(): } + def test_header_update(): url = "http://example.org/echo_headers" with httpx.Client(transport=httpx.MockTransport(echo_headers)) as client: @@ -122,12 +126,15 @@ def test_header_update(): } + def test_header_repeated_items(): url = "http://example.org/echo_headers" with httpx.Client( transport=httpx.MockTransport(echo_repeated_headers_items) ) as client: - response = client.get(url, headers=[("x-header", "1"), ("x-header", "2,3")]) + response = client.get( + url, headers=[("x-header", "1"), ("x-header", "2,3")] + ) assert response.status_code == 200 @@ -139,12 +146,15 @@ def test_header_repeated_items(): ] + def test_header_repeated_multi_items(): url = "http://example.org/echo_headers" with httpx.Client( transport=httpx.MockTransport(echo_repeated_headers_multi_items) ) as client: - response = client.get(url, headers=[("x-header", "1"), ("x-header", "2,3")]) + response = client.get( + url, headers=[("x-header", "1"), ("x-header", "2,3")] + ) assert response.status_code == 200 @@ -153,6 +163,7 @@ def test_header_repeated_multi_items(): assert ["x-header", "2,3"] in echoed_headers + def test_remove_default_header(): """ Remove a default header from the Client. @@ -175,12 +186,14 @@ def test_remove_default_header(): } + def test_header_does_not_exist(): headers = httpx.Headers({"foo": "bar"}) with pytest.raises(KeyError): del headers["baz"] + def test_header_with_incorrect_value(): with pytest.raises( TypeError, @@ -189,6 +202,7 @@ def test_header_with_incorrect_value(): httpx.Headers({"foo": None}) # type: ignore + def test_host_with_auth_and_port_in_url(): """ The Host header should only include the hostname, or hostname:port @@ -213,6 +227,7 @@ def test_host_with_auth_and_port_in_url(): } + def test_host_with_non_default_port_in_url(): """ If the URL includes a non-default port, then it should be included in @@ -236,11 +251,13 @@ def test_host_with_non_default_port_in_url(): } + def test_request_auto_headers(): request = httpx.Request("GET", "https://www.example.org/") assert "host" in request.headers + def test_same_origin(): origin = httpx.URL("https://example.com") request = httpx.Request("GET", "HTTPS://EXAMPLE.COM:443") @@ -251,6 +268,7 @@ def test_same_origin(): assert headers["Host"] == request.url.netloc.decode("ascii") + def test_not_same_origin(): origin = httpx.URL("https://example.com") request = httpx.Request("GET", "HTTP://EXAMPLE.COM:80") @@ -261,6 +279,7 @@ def test_not_same_origin(): assert headers["Host"] == origin.netloc.decode("ascii") + def test_is_https_redirect(): url = httpx.URL("https://example.com") request = httpx.Request( @@ -273,6 +292,7 @@ def test_is_https_redirect(): assert "Authorization" in headers + def test_is_not_https_redirect(): url = httpx.URL("https://www.example.com") request = httpx.Request( @@ -285,6 +305,7 @@ def test_is_not_https_redirect(): assert "Authorization" not in headers + def test_is_not_https_redirect_if_not_default_ports(): url = httpx.URL("https://example.com:1337") request = httpx.Request( diff --git a/tests/client/sync/test_properties.py b/tests/client/sync/test_properties.py index 83f85f0e..980224a7 100644 --- a/tests/client/sync/test_properties.py +++ b/tests/client/sync/test_properties.py @@ -1,6 +1,9 @@ +import pytest + import httpx + def test_client_base_url(): with httpx.Client() as client: client.base_url = "https://www.example.org/" # type: ignore @@ -8,6 +11,7 @@ def test_client_base_url(): assert client.base_url == "https://www.example.org/" + def test_client_base_url_without_trailing_slash(): with httpx.Client() as client: client.base_url = "https://www.example.org/path" # type: ignore @@ -15,6 +19,7 @@ def test_client_base_url_without_trailing_slash(): assert client.base_url == "https://www.example.org/path/" + def test_client_base_url_with_trailing_slash(): client = httpx.Client() client.base_url = "https://www.example.org/path/" # type: ignore @@ -22,6 +27,7 @@ def test_client_base_url_with_trailing_slash(): assert client.base_url == "https://www.example.org/path/" + def test_client_headers(): with httpx.Client() as client: client.headers = {"a": "b"} # type: ignore @@ -29,6 +35,7 @@ def test_client_headers(): assert client.headers["A"] == "b" + def test_client_cookies(): with httpx.Client() as client: client.cookies = {"a": "b"} # type: ignore @@ -38,6 +45,7 @@ def test_client_cookies(): assert mycookies[0].name == "a" and mycookies[0].value == "b" + def test_client_timeout(): expected_timeout = 12.0 with httpx.Client() as client: @@ -50,6 +58,7 @@ def test_client_timeout(): assert client.timeout.pool == expected_timeout + def test_client_event_hooks(): def on_request(request): pass # pragma: no cover @@ -59,6 +68,7 @@ def test_client_event_hooks(): assert client.event_hooks == {"request": [on_request], "response": []} + def test_client_trust_env(): with httpx.Client() as client: assert client.trust_env diff --git a/tests/client/sync/test_proxies.py b/tests/client/sync/test_proxies.py index 2aa5d92b..e7ebea8b 100644 --- a/tests/client/sync/test_proxies.py +++ b/tests/client/sync/test_proxies.py @@ -13,6 +13,7 @@ def url_to_origin(url: str) -> httpcore.URL: return httpcore.URL(scheme=u.raw_scheme, host=u.raw_host, port=u.port, target="/") + def test_socks_proxy(): url = httpx.URL("http://www.example.com") @@ -80,8 +81,11 @@ PROXY_URL = "http://[::1]" ), ], ) + def test_transport_for_request(url, proxies, expected): - mounts = {key: httpx.HTTPTransport(proxy=value) for key, value in proxies.items()} + mounts = { + key: httpx.HTTPTransport(proxy=value) for key, value in proxies.items() + } with httpx.Client(mounts=mounts) as client: transport = client._transport_for_url(httpx.URL(url)) @@ -93,6 +97,7 @@ def test_transport_for_request(url, proxies, expected): assert transport._pool._proxy_url == url_to_origin(expected) + @pytest.mark.network def test_proxy_close(): try: @@ -103,6 +108,7 @@ def test_proxy_close(): client.close() + def test_unsupported_proxy_scheme(): with pytest.raises(ValueError): httpx.Client(proxy="ftp://127.0.0.1") @@ -205,6 +211,7 @@ def test_unsupported_proxy_scheme(): ), ], ) + def test_proxies_environ(monkeypatch, url, env, expected): for name, value in env.items(): monkeypatch.setenv(name, value) @@ -229,8 +236,11 @@ def test_proxies_environ(monkeypatch, url, env, expected): ({"all://": "http://127.0.0.1"}, True), ], ) + def test_for_deprecated_proxy_params(proxies, is_valid): - mounts = {key: httpx.HTTPTransport(proxy=value) for key, value in proxies.items()} + mounts = { + key: httpx.HTTPTransport(proxy=value) for key, value in proxies.items() + } if not is_valid: with pytest.raises(ValueError): @@ -239,6 +249,7 @@ def test_for_deprecated_proxy_params(proxies, is_valid): httpx.Client(mounts=mounts) + def test_proxy_with_mounts(): proxy_transport = httpx.HTTPTransport(proxy="http://127.0.0.1") diff --git a/tests/client/sync/test_queryparams.py b/tests/client/sync/test_queryparams.py index 0ecdbaba..740c7a0a 100644 --- a/tests/client/sync/test_queryparams.py +++ b/tests/client/sync/test_queryparams.py @@ -1,3 +1,5 @@ +import pytest + import httpx @@ -5,12 +7,14 @@ def hello_world(request: httpx.Request) -> httpx.Response: return httpx.Response(200, text="Hello, world") + def test_client_queryparams(): client = httpx.Client(params={"a": "b"}) assert isinstance(client.params, httpx.QueryParams) assert client.params["a"] == "b" + def test_client_queryparams_string(): with httpx.Client(params="a=b") as client: assert isinstance(client.params, httpx.QueryParams) @@ -22,6 +26,7 @@ def test_client_queryparams_string(): assert client.params["a"] == "b" + def test_client_queryparams_echo(): url = "http://example.org/echo_queryparams" client_queryparams = "first=str" diff --git a/tests/client/sync/test_redirects.py b/tests/client/sync/test_redirects.py index c24c9a8b..29bb2a8f 100644 --- a/tests/client/sync/test_redirects.py +++ b/tests/client/sync/test_redirects.py @@ -113,6 +113,7 @@ def redirects(request: httpx.Request) -> httpx.Response: return httpx.Response(200, html="Hello, world!") + def test_redirect_301(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.post( @@ -123,6 +124,7 @@ def test_redirect_301(): assert len(response.history) == 1 + def test_redirect_302(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.post( @@ -133,14 +135,18 @@ def test_redirect_302(): assert len(response.history) == 1 + def test_redirect_303(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: - response = client.get("https://example.org/redirect_303", follow_redirects=True) + response = client.get( + "https://example.org/redirect_303", follow_redirects=True + ) assert response.status_code == httpx.codes.OK assert response.url == "https://example.org/" assert len(response.history) == 1 + def test_next_request(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: request = client.build_request("POST", "https://example.org/redirect_303") @@ -155,6 +161,7 @@ def test_next_request(): assert response.next_request is None + def test_head_redirect(): """ Contrary to Requests, redirects remain enabled by default for HEAD requests. @@ -170,6 +177,7 @@ def test_head_redirect(): assert response.text == "" + def test_relative_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.get( @@ -180,6 +188,7 @@ def test_relative_redirect(): assert len(response.history) == 1 + def test_malformed_redirect(): # https://github.com/encode/httpx/issues/771 with httpx.Client(transport=httpx.MockTransport(redirects)) as client: @@ -191,6 +200,7 @@ def test_malformed_redirect(): assert len(response.history) == 1 + def test_no_scheme_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.get( @@ -201,6 +211,7 @@ def test_no_scheme_redirect(): assert len(response.history) == 1 + def test_fragment_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.get( @@ -211,6 +222,7 @@ def test_fragment_redirect(): assert len(response.history) == 1 + def test_multiple_redirects(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: response = client.get( @@ -229,6 +241,7 @@ def test_multiple_redirects(): assert len(response.history[1].history) == 1 + def test_too_many_redirects(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: with pytest.raises(httpx.TooManyRedirects): @@ -237,12 +250,14 @@ def test_too_many_redirects(): ) + def test_redirect_loop(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: with pytest.raises(httpx.TooManyRedirects): client.get("https://example.org/redirect_loop", follow_redirects=True) + def test_cross_domain_redirect_with_auth_header(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "https://example.com/cross_domain" @@ -252,6 +267,7 @@ def test_cross_domain_redirect_with_auth_header(): assert "authorization" not in response.json()["headers"] + def test_cross_domain_https_redirect_with_auth_header(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "http://example.com/cross_domain" @@ -261,6 +277,7 @@ def test_cross_domain_https_redirect_with_auth_header(): assert "authorization" not in response.json()["headers"] + def test_cross_domain_redirect_with_auth(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "https://example.com/cross_domain" @@ -269,6 +286,7 @@ def test_cross_domain_redirect_with_auth(): assert "authorization" not in response.json()["headers"] + def test_same_domain_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "https://example.org/cross_domain" @@ -278,6 +296,7 @@ def test_same_domain_redirect(): assert response.json()["headers"]["authorization"] == "abc" + def test_same_domain_https_redirect_with_auth_header(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "http://example.org/cross_domain" @@ -287,6 +306,7 @@ def test_same_domain_https_redirect_with_auth_header(): assert response.json()["headers"]["authorization"] == "abc" + def test_body_redirect(): """ A 308 redirect should preserve the request body. @@ -300,6 +320,7 @@ def test_body_redirect(): assert "content-length" in response.json()["headers"] + def test_no_body_redirect(): """ A 303 redirect should remove the request body. @@ -313,6 +334,7 @@ def test_no_body_redirect(): assert "content-length" not in response.json()["headers"] + def test_can_stream_if_no_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "https://example.org/redirect_301" @@ -330,6 +352,7 @@ class ConsumeBodyTransport(httpx.MockTransport): return self.handler(request) # type: ignore[return-value] + def test_cannot_redirect_streaming_body(): with httpx.Client(transport=ConsumeBodyTransport(redirects)) as client: url = "https://example.org/redirect_body" @@ -341,6 +364,7 @@ def test_cannot_redirect_streaming_body(): client.post(url, content=streaming_body(), follow_redirects=True) + def test_cross_subdomain_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: url = "https://example.com/cross_subdomain" @@ -348,6 +372,7 @@ def test_cross_subdomain_redirect(): assert response.url == "https://www.example.org/cross_subdomain" + def cookie_sessions(request: httpx.Request) -> httpx.Response: if request.url.path == "/": cookie = request.headers.get("Cookie") @@ -381,6 +406,7 @@ def cookie_sessions(request: httpx.Request) -> httpx.Response: return httpx.Response(status_code, headers=headers) + def test_redirect_cookie_behavior(): with httpx.Client( transport=httpx.MockTransport(cookie_sessions), follow_redirects=True @@ -411,6 +437,7 @@ def test_redirect_cookie_behavior(): assert response.text == "Not logged in" + def test_redirect_custom_scheme(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: with pytest.raises(httpx.UnsupportedProtocol) as e: @@ -420,7 +447,10 @@ def test_redirect_custom_scheme(): assert str(e.value) == "Scheme 'market' not supported." + def test_invalid_redirect(): with httpx.Client(transport=httpx.MockTransport(redirects)) as client: with pytest.raises(httpx.RemoteProtocolError): - client.get("http://example.org/invalid_redirect", follow_redirects=True) + client.get( + "http://example.org/invalid_redirect", follow_redirects=True + )