diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e1a953dc97..899701174b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -211,9 +211,10 @@ this is where our previously generated `client.pem` comes in: ``` import httpx -proxies = {"all": "http://127.0.0.1:8080/"} +proxy = "https://127.0.0.1:8080" +verify = "/path/to/client.pem" -with httpx.Client(proxies=proxies, verify="/path/to/client.pem") as client: +with httpx.Client(proxy=proxy, verify=verify) as client: response = client.get("https://example.org") print(response.status_code) # should print 200 ``` diff --git a/CHANGELOG.md b/CHANGELOG.md index 47ac88c834..decdf7db33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * Respect the `http1` argument while configuring proxy transports. (#3023) * Fix RFC 2069 mode digest authentication. (#3045) +### Removed + +* Recently deprecated `proxies` argument has been removed. (#3071) +* Per request `cookies` argument is not supporting anymore. (#3071) +* Non-Mapping objects for `data` argument is no longer allowed. (#3071) + ## 0.26.0 (20th December, 2023) ### Added diff --git a/httpx/_api.py b/httpx/_api.py index b5821cc49e..d247a96860 100644 --- a/httpx/_api.py +++ b/httpx/_api.py @@ -11,7 +11,6 @@ CertTypes, CookieTypes, HeaderTypes, - ProxiesTypes, ProxyTypes, QueryParamTypes, RequestContent, @@ -36,7 +35,6 @@ def request( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, follow_redirects: bool = False, verify: VerifyTypes = True, @@ -68,7 +66,6 @@ def request( * **auth** - *(optional)* An authentication class to use when sending the request. * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **proxies** - *(optional)* A dictionary mapping proxy keys to proxy URLs. * **timeout** - *(optional)* The timeout configuration to use when sending the request. * **follow_redirects** - *(optional)* Enables or disables HTTP redirects. @@ -97,7 +94,6 @@ def request( with Client( cookies=cookies, proxy=proxy, - proxies=proxies, cert=cert, verify=verify, timeout=timeout, @@ -131,7 +127,6 @@ def stream( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, follow_redirects: bool = False, verify: VerifyTypes = True, @@ -151,7 +146,6 @@ def stream( with Client( cookies=cookies, proxy=proxy, - proxies=proxies, cert=cert, verify=verify, timeout=timeout, @@ -180,7 +174,6 @@ def get( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -203,7 +196,6 @@ def get( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -220,7 +212,6 @@ def options( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -243,7 +234,6 @@ def options( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -260,7 +250,6 @@ def head( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -283,7 +272,6 @@ def head( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -304,7 +292,6 @@ def post( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -328,7 +315,6 @@ def post( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -349,7 +335,6 @@ def put( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -373,7 +358,6 @@ def put( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -394,7 +378,6 @@ def patch( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -418,7 +401,6 @@ def patch( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, @@ -435,7 +417,6 @@ def delete( cookies: CookieTypes | None = None, auth: AuthTypes | None = None, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, follow_redirects: bool = False, cert: CertTypes | None = None, verify: VerifyTypes = True, @@ -458,7 +439,6 @@ def delete( cookies=cookies, auth=auth, proxy=proxy, - proxies=proxies, follow_redirects=follow_redirects, cert=cert, verify=verify, diff --git a/httpx/_client.py b/httpx/_client.py index 1f2145d12e..49ea419601 100644 --- a/httpx/_client.py +++ b/httpx/_client.py @@ -4,7 +4,6 @@ import enum import logging import typing -import warnings from contextlib import asynccontextmanager, contextmanager from types import TracebackType @@ -37,7 +36,6 @@ CertTypes, CookieTypes, HeaderTypes, - ProxiesTypes, ProxyTypes, QueryParamTypes, RequestContent, @@ -210,24 +208,18 @@ def _enforce_trailing_slash(self, url: URL) -> URL: return url.copy_with(raw_path=url.raw_path + b"/") def _get_proxy_map( - self, proxies: ProxiesTypes | None, allow_env_proxies: bool + self, proxy: ProxyTypes | None, allow_env_proxies: bool ) -> dict[str, Proxy | None]: - if proxies is None: + if proxy is None: if allow_env_proxies: return { key: None if url is None else Proxy(url=url) for key, url in get_environment_proxies().items() } return {} - if isinstance(proxies, dict): - new_proxies = {} - for key, value in proxies.items(): - proxy = Proxy(url=value) if isinstance(value, (str, URL)) else value - new_proxies[str(key)] = proxy - return new_proxies - else: - proxy = Proxy(url=proxies) if isinstance(proxies, (str, URL)) else proxies - return {"all://": proxy} + + universal_proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy + return {"all://": universal_proxy} @property def timeout(self) -> Timeout: @@ -327,15 +319,14 @@ def build_request( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, extensions: RequestExtensions | None = None, ) -> Request: """ Build and return a request instance. - * The `params`, `headers` and `cookies` arguments - are merged with any values set on the client. + * The `params` and `headers` arguments are merged with any values + set on the client. * The `url` argument is merged with any `base_url` set on the client. See also: [Request instances][0] @@ -344,7 +335,6 @@ def build_request( """ url = self._merge_url(url) headers = self._merge_headers(headers) - cookies = self._merge_cookies(cookies) params = self._merge_queryparams(params) extensions = {} if extensions is None else extensions if "timeout" not in extensions: @@ -354,6 +344,7 @@ def build_request( else Timeout(timeout) ) extensions = dict(**extensions, timeout=timeout.as_dict()) + cookies = Cookies(self.cookies) return Request( method, url, @@ -389,17 +380,6 @@ def _merge_url(self, url: URLTypes) -> URL: return self.base_url.copy_with(raw_path=merge_raw_path) return merge_url - def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None: - """ - Merge a cookies argument together with any cookies on the client, - to create the cookies used for the outgoing request. - """ - if cookies or self.cookies: - merged_cookies = Cookies(self.cookies) - merged_cookies.update(cookies) - return merged_cookies - return cookies - def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None: """ Merge a headers argument together with any headers on the client, @@ -595,8 +575,6 @@ class Client(BaseClient): * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be enabled. Defaults to `False`. * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **proxies** - *(optional)* A dictionary mapping proxy keys to proxy - URLs. * **timeout** - *(optional)* The timeout configuration to use when sending requests. * **limits** - *(optional)* The limits configuration to use. @@ -627,7 +605,6 @@ def __init__( http1: bool = True, http2: bool = False, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, mounts: None | (typing.Mapping[str, BaseTransport | None]) = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, follow_redirects: bool = False, @@ -663,17 +640,8 @@ def __init__( "Make sure to install httpx using `pip install httpx[http2]`." ) from None - if proxies: - message = ( - "The 'proxies' argument is now deprecated." - " Use 'proxy' or 'mounts' instead." - ) - warnings.warn(message, DeprecationWarning) - if proxy: - raise RuntimeError("Use either `proxy` or 'proxies', not both.") - allow_env_proxies = trust_env and app is None and transport is None - proxy_map = self._get_proxy_map(proxies or proxy, allow_env_proxies) + proxy_map = self._get_proxy_map(proxy, allow_env_proxies) self._transport = self._init_transport( verify=verify, @@ -774,7 +742,6 @@ def request( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -796,14 +763,6 @@ def request( [0]: /advanced/#merging-of-configuration """ - if cookies is not None: - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning) - request = self.build_request( method=method, url=url, @@ -813,7 +772,6 @@ def request( json=json, params=params, headers=headers, - cookies=cookies, timeout=timeout, extensions=extensions, ) @@ -831,7 +789,6 @@ def stream( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -856,7 +813,6 @@ def stream( json=json, params=params, headers=headers, - cookies=cookies, timeout=timeout, extensions=extensions, ) @@ -1033,7 +989,6 @@ def get( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1049,7 +1004,6 @@ def get( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1062,7 +1016,6 @@ def options( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1078,7 +1031,6 @@ def options( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1091,7 +1043,6 @@ def head( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1107,7 +1058,6 @@ def head( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1124,7 +1074,6 @@ def post( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1144,7 +1093,6 @@ def post( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1161,7 +1109,6 @@ def put( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1181,7 +1128,6 @@ def put( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1198,7 +1144,6 @@ def patch( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1218,7 +1163,6 @@ def patch( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1231,7 +1175,6 @@ def delete( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1247,7 +1190,6 @@ def delete( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1256,7 +1198,7 @@ def delete( def close(self) -> None: """ - Close transport and proxies. + Close transport and mounts. """ if self._state != ClientState.CLOSED: self._state = ClientState.CLOSED @@ -1333,8 +1275,6 @@ class AsyncClient(BaseClient): * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be enabled. Defaults to `False`. * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. - * **proxies** - *(optional)* A dictionary mapping HTTP protocols to proxy - URLs. * **timeout** - *(optional)* The timeout configuration to use when sending requests. * **limits** - *(optional)* The limits configuration to use. @@ -1365,7 +1305,6 @@ def __init__( http1: bool = True, http2: bool = False, proxy: ProxyTypes | None = None, - proxies: ProxiesTypes | None = None, mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None, timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, follow_redirects: bool = False, @@ -1402,17 +1341,8 @@ def __init__( "Make sure to install httpx using `pip install httpx[http2]`." ) from None - if proxies: - message = ( - "The 'proxies' argument is now deprecated." - " Use 'proxy' or 'mounts' instead." - ) - warnings.warn(message, DeprecationWarning) - if proxy: - raise RuntimeError("Use either `proxy` or 'proxies', not both.") - allow_env_proxies = trust_env and app is None and transport is None - proxy_map = self._get_proxy_map(proxies or proxy, allow_env_proxies) + proxy_map = self._get_proxy_map(proxy, allow_env_proxies) self._transport = self._init_transport( verify=verify, @@ -1513,7 +1443,6 @@ async def request( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1535,15 +1464,6 @@ async def request( [0]: /advanced/#merging-of-configuration """ - - if cookies is not None: # pragma: no cover - message = ( - "Setting per-request cookies=<...> is being deprecated, because " - "the expected behaviour on cookie persistence is ambiguous. Set " - "cookies directly on the client instance instead." - ) - warnings.warn(message, DeprecationWarning) - request = self.build_request( method=method, url=url, @@ -1553,7 +1473,6 @@ async def request( json=json, params=params, headers=headers, - cookies=cookies, timeout=timeout, extensions=extensions, ) @@ -1571,7 +1490,6 @@ async def stream( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1596,7 +1514,6 @@ async def stream( json=json, params=params, headers=headers, - cookies=cookies, timeout=timeout, extensions=extensions, ) @@ -1773,7 +1690,6 @@ async def get( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1789,7 +1705,6 @@ async def get( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1802,7 +1717,6 @@ async def options( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1818,7 +1732,6 @@ async def options( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1831,7 +1744,6 @@ async def head( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1847,7 +1759,6 @@ async def head( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1864,7 +1775,6 @@ async def post( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1884,7 +1794,6 @@ async def post( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1901,7 +1810,6 @@ async def put( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1921,7 +1829,6 @@ async def put( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1938,7 +1845,6 @@ async def patch( json: typing.Any | None = None, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1958,7 +1864,6 @@ async def patch( json=json, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1971,7 +1876,6 @@ async def delete( *, params: QueryParamTypes | None = None, headers: HeaderTypes | None = None, - cookies: CookieTypes | None = None, auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, @@ -1987,7 +1891,6 @@ async def delete( url, params=params, headers=headers, - cookies=cookies, auth=auth, follow_redirects=follow_redirects, timeout=timeout, @@ -1996,15 +1899,15 @@ async def delete( async def aclose(self) -> None: """ - Close transport and proxies. + Close transport and mounts. """ if self._state != ClientState.CLOSED: self._state = ClientState.CLOSED await self._transport.aclose() - for proxy in self._mounts.values(): - if proxy is not None: - await proxy.aclose() + for transport in self._mounts.values(): + if transport is not None: + await transport.aclose() async def __aenter__(self: U) -> U: if self._state != ClientState.UNOPENED: diff --git a/httpx/_content.py b/httpx/_content.py index 10b574bb3d..9567e0b147 100644 --- a/httpx/_content.py +++ b/httpx/_content.py @@ -1,7 +1,6 @@ from __future__ import annotations import inspect -import warnings from json import dumps as json_dumps from typing import ( Any, @@ -9,7 +8,6 @@ AsyncIterator, Iterable, Iterator, - Mapping, ) from urllib.parse import urlencode @@ -190,18 +188,6 @@ def encode_request( Handles encoding the given `content`, `data`, `files`, and `json`, returning a two-tuple of (, ). """ - if data is not None and not isinstance(data, Mapping): - # We prefer to separate `content=` - # for raw request content, and `data=
` for url encoded or - # multipart form content. - # - # However for compat with requests, we *do* still support - # `data=` usages. We deal with that case here, treating it - # as if `content=<...>` had been supplied instead. - message = "Use 'content=<...>' to upload raw bytes/text content." - warnings.warn(message, DeprecationWarning) - return encode_content(data) - if content is not None: return encode_content(content) elif files: diff --git a/httpx/_main.py b/httpx/_main.py index 72657f8ca3..354939e7d4 100644 --- a/httpx/_main.py +++ b/httpx/_main.py @@ -479,6 +479,7 @@ def main( timeout=timeout, verify=verify, http2=http2, + cookies=dict(cookies), ) as client: with client.stream( method, @@ -489,7 +490,6 @@ def main( files=files, # type: ignore json=json, headers=headers, - cookies=dict(cookies), auth=auth, follow_redirects=follow_redirects, extensions={"trace": functools.partial(trace, verbose=verbose)}, diff --git a/httpx/_types.py b/httpx/_types.py index 649d101d54..f37031717e 100644 --- a/httpx/_types.py +++ b/httpx/_types.py @@ -79,7 +79,6 @@ "Timeout", ] ProxyTypes = Union[URLTypes, "Proxy"] -ProxiesTypes = Union[ProxyTypes, Dict[URLTypes, Union[None, ProxyTypes]]] AuthTypes = Union[ Tuple[Union[str, bytes], Union[str, bytes]], diff --git a/tests/client/test_async_client.py b/tests/client/test_async_client.py index 8d7eaa3c58..87606cc462 100644 --- a/tests/client/test_async_client.py +++ b/tests/client/test_async_client.py @@ -373,3 +373,13 @@ async def test_server_extensions(server): response = await client.get(url) assert response.status_code == 200 assert response.extensions["http_version"] == b"HTTP/1.1" + + +@pytest.mark.anyio +async def test_async_client_close(server): + mounts = {"all://": httpx.MockTransport(hello_world)} + try: + client = httpx.AsyncClient(mounts=mounts) + await client.get(server.url) + finally: + await client.aclose() diff --git a/tests/client/test_client.py b/tests/client/test_client.py index 2951e01b8a..7def87b4a3 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -167,6 +167,13 @@ def test_put(server): assert response.reason_phrase == "OK" +def test_put_json(server): + with httpx.Client() as client: + response = client.put(server.url, json={"text": "Hello, world!"}) + assert response.status_code == 200 + assert response.reason_phrase == "OK" + + def test_patch(server): with httpx.Client() as client: response = client.patch(server.url, content=b"Hello, world!") @@ -460,3 +467,12 @@ def cp1252_but_no_content_type(request): assert response.reason_phrase == "OK" assert response.encoding == "ISO-8859-1" assert response.text == text + + +def test_client_close(server): + mounts = {"all://": httpx.MockTransport(hello_world)} + try: + client = httpx.Client(mounts=mounts) + client.get(server.url) + finally: + client.close() diff --git a/tests/client/test_cookies.py b/tests/client/test_cookies.py index f0c8352593..77bb9b47f6 100644 --- a/tests/client/test_cookies.py +++ b/tests/client/test_cookies.py @@ -1,7 +1,5 @@ from http.cookiejar import Cookie, CookieJar -import pytest - import httpx @@ -31,21 +29,6 @@ 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. - """ - url = "http://example.org/echo_cookies" - cookies = {"example-name": "example-value"} - - client = httpx.Client(transport=httpx.MockTransport(get_and_set_cookies)) - with pytest.warns(DeprecationWarning): - response = client.get(url, cookies=cookies) - - assert response.status_code == 200 - 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. diff --git a/tests/client/test_proxies.py b/tests/client/test_proxies.py index 7bba1ab2c3..6ae45612ba 100644 --- a/tests/client/test_proxies.py +++ b/tests/client/test_proxies.py @@ -14,27 +14,14 @@ def url_to_origin(url: str) -> httpcore.URL: @pytest.mark.parametrize( - ["proxies", "expected_proxies"], + ["proxy", "expected_proxies"], [ ("http://127.0.0.1", [("all://", "http://127.0.0.1")]), - ({"all://": "http://127.0.0.1"}, [("all://", "http://127.0.0.1")]), - ( - {"http://": "http://127.0.0.1", "https://": "https://127.0.0.1"}, - [("http://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")], - ), (httpx.Proxy("http://127.0.0.1"), [("all://", "http://127.0.0.1")]), - ( - { - "https://": httpx.Proxy("https://127.0.0.1"), - "all://": "http://127.0.0.1", - }, - [("all://", "http://127.0.0.1"), ("https://", "https://127.0.0.1")], - ), ], ) -def test_proxies_parameter(proxies, expected_proxies): - with pytest.warns(DeprecationWarning): - client = httpx.Client(proxies=proxies) +def test_proxy_parameter(proxy, expected_proxies): + client = httpx.Client(proxy=proxy) client_patterns = [p.pattern for p in client._mounts.keys()] client_proxies = list(client._mounts.values()) @@ -48,22 +35,6 @@ def test_proxies_parameter(proxies, expected_proxies): assert len(expected_proxies) == len(client._mounts) -def test_socks_proxy_deprecated(): - url = httpx.URL("http://www.example.com") - - with pytest.warns(DeprecationWarning): - client = httpx.Client(proxies="socks5://localhost/") - transport = client._transport_for_url(url) - assert isinstance(transport, httpx.HTTPTransport) - assert isinstance(transport._pool, httpcore.SOCKSProxy) - - with pytest.warns(DeprecationWarning): - async_client = httpx.AsyncClient(proxies="socks5://localhost/") - async_transport = async_client._transport_for_url(url) - assert isinstance(async_transport, httpx.AsyncHTTPTransport) - assert isinstance(async_transport._pool, httpcore.AsyncSOCKSProxy) - - def test_socks_proxy(): url = httpx.URL("http://www.example.com") @@ -78,108 +49,6 @@ def test_socks_proxy(): assert isinstance(async_transport._pool, httpcore.AsyncSOCKSProxy) -PROXY_URL = "http://[::1]" - - -@pytest.mark.parametrize( - ["url", "proxies", "expected"], - [ - ("http://example.com", None, None), - ("http://example.com", {}, None), - ("http://example.com", {"https://": PROXY_URL}, None), - ("http://example.com", {"http://example.net": PROXY_URL}, None), - # Using "*" should match any domain name. - ("http://example.com", {"http://*": PROXY_URL}, PROXY_URL), - ("https://example.com", {"http://*": PROXY_URL}, None), - # Using "example.com" should match example.com, but not www.example.com - ("http://example.com", {"http://example.com": PROXY_URL}, PROXY_URL), - ("http://www.example.com", {"http://example.com": PROXY_URL}, None), - # Using "*.example.com" should match www.example.com, but not example.com - ("http://example.com", {"http://*.example.com": PROXY_URL}, None), - ("http://www.example.com", {"http://*.example.com": PROXY_URL}, PROXY_URL), - # Using "*example.com" should match example.com and www.example.com - ("http://example.com", {"http://*example.com": PROXY_URL}, PROXY_URL), - ("http://www.example.com", {"http://*example.com": PROXY_URL}, PROXY_URL), - ("http://wwwexample.com", {"http://*example.com": PROXY_URL}, None), - # ... - ("http://example.com:443", {"http://example.com": PROXY_URL}, PROXY_URL), - ("http://example.com", {"all://": PROXY_URL}, PROXY_URL), - ("http://example.com", {"all://": PROXY_URL, "http://example.com": None}, None), - ("http://example.com", {"http://": PROXY_URL}, PROXY_URL), - ("http://example.com", {"all://example.com": PROXY_URL}, PROXY_URL), - ("http://example.com", {"http://example.com": PROXY_URL}, PROXY_URL), - ("http://example.com", {"http://example.com:80": PROXY_URL}, PROXY_URL), - ("http://example.com:8080", {"http://example.com:8080": PROXY_URL}, PROXY_URL), - ("http://example.com:8080", {"http://example.com": PROXY_URL}, PROXY_URL), - ( - "http://example.com", - { - "all://": PROXY_URL + ":1", - "http://": PROXY_URL + ":2", - "all://example.com": PROXY_URL + ":3", - "http://example.com": PROXY_URL + ":4", - }, - PROXY_URL + ":4", - ), - ( - "http://example.com", - { - "all://": PROXY_URL + ":1", - "http://": PROXY_URL + ":2", - "all://example.com": PROXY_URL + ":3", - }, - PROXY_URL + ":3", - ), - ( - "http://example.com", - {"all://": PROXY_URL + ":1", "http://": PROXY_URL + ":2"}, - PROXY_URL + ":2", - ), - ], -) -def test_transport_for_request(url, proxies, expected): - if proxies: - with pytest.warns(DeprecationWarning): - client = httpx.Client(proxies=proxies) - else: - client = httpx.Client(proxies=proxies) - - transport = client._transport_for_url(httpx.URL(url)) - - if expected is None: - assert transport is client._transport - else: - assert isinstance(transport, httpx.HTTPTransport) - assert isinstance(transport._pool, httpcore.HTTPProxy) - assert transport._pool._proxy_url == url_to_origin(expected) - - -@pytest.mark.anyio -@pytest.mark.network -async def test_async_proxy_close(): - try: - with pytest.warns(DeprecationWarning): - client = httpx.AsyncClient(proxies={"https://": PROXY_URL}) - await client.get("http://example.com") - finally: - await client.aclose() - - -@pytest.mark.network -def test_sync_proxy_close(): - try: - with pytest.warns(DeprecationWarning): - client = httpx.Client(proxies={"https://": PROXY_URL}) - client.get("http://example.com") - finally: - client.close() - - -def test_unsupported_proxy_scheme_deprecated(): - with pytest.warns(DeprecationWarning), pytest.raises(ValueError): - httpx.Client(proxies="ftp://127.0.0.1") - - def test_unsupported_proxy_scheme(): with pytest.raises(ValueError): httpx.Client(proxy="ftp://127.0.0.1") @@ -296,40 +165,6 @@ def test_proxies_environ(monkeypatch, client_class, url, env, expected): assert transport._pool._proxy_url == url_to_origin(expected) -@pytest.mark.parametrize( - ["proxies", "is_valid"], - [ - ({"http": "http://127.0.0.1"}, False), - ({"https": "http://127.0.0.1"}, False), - ({"all": "http://127.0.0.1"}, False), - ({"http://": "http://127.0.0.1"}, True), - ({"https://": "http://127.0.0.1"}, True), - ({"all://": "http://127.0.0.1"}, True), - ], -) -def test_for_deprecated_proxy_params(proxies, is_valid): - with pytest.warns(DeprecationWarning): - if not is_valid: - with pytest.raises(ValueError): - httpx.Client(proxies=proxies) - else: - httpx.Client(proxies=proxies) - - -def test_proxy_and_proxies_together(): - with pytest.warns(DeprecationWarning), pytest.raises( - RuntimeError, - ): - httpx.Client(proxies={"all://": "http://127.0.0.1"}, proxy="http://127.0.0.1") - - with pytest.warns(DeprecationWarning), pytest.raises( - RuntimeError, - ): - httpx.AsyncClient( - proxies={"all://": "http://127.0.0.1"}, proxy="http://127.0.0.1" - ) - - def test_proxy_with_mounts(): proxy_transport = httpx.HTTPTransport(proxy="http://127.0.0.1") client = httpx.Client(mounts={"http://": proxy_transport}) diff --git a/tests/test_content.py b/tests/test_content.py index 21c92dd799..a189d61eb1 100644 --- a/tests/test_content.py +++ b/tests/test_content.py @@ -36,9 +36,7 @@ async def test_bytes_content(): assert sync_content == b"Hello, world!" assert async_content == b"Hello, world!" - # Support 'data' for compat with requests. - with pytest.warns(DeprecationWarning): - request = httpx.Request(method, url, data=b"Hello, world!") # type: ignore + request = httpx.Request(method, url, content=b"Hello, world!") assert isinstance(request.stream, typing.Iterable) assert isinstance(request.stream, typing.AsyncIterable) @@ -111,9 +109,7 @@ def hello_world() -> typing.Iterator[bytes]: with pytest.raises(httpx.StreamConsumed): list(request.stream) - # Support 'data' for compat with requests. - with pytest.warns(DeprecationWarning): - request = httpx.Request(method, url, data=hello_world()) # type: ignore + request = httpx.Request(method, url, content=hello_world()) assert isinstance(request.stream, typing.Iterable) assert not isinstance(request.stream, typing.AsyncIterable) @@ -147,9 +143,7 @@ async def hello_world() -> typing.AsyncIterator[bytes]: with pytest.raises(httpx.StreamConsumed): [part async for part in request.stream] - # Support 'data' for compat with requests. - with pytest.warns(DeprecationWarning): - request = httpx.Request(method, url, data=hello_world()) # type: ignore + request = httpx.Request(method, url, content=hello_world()) assert not isinstance(request.stream, typing.Iterable) assert isinstance(request.stream, typing.AsyncIterable) diff --git a/tests/test_utils.py b/tests/test_utils.py index 0ef87d18d8..357458d519 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -290,3 +290,8 @@ def test_pattern_priority(): URLPattern("http://"), URLPattern("all://"), ] + + +def test_plain_pattern(): + with pytest.raises(ValueError): + URLPattern("http")