From 3d06cc14ad82ce4c207449b593955c23bd5e4d88 Mon Sep 17 00:00:00 2001 From: Cycloctane Date: Mon, 6 Jan 2025 22:01:32 +0800 Subject: [PATCH] Use kwargs in aiohttp.client.request (#10300) --- CHANGES/10300.feature.rst | 2 + aiohttp/client.py | 173 ++++++++++++++------------------ docs/spelling_wordlist.txt | 2 + tests/test_client_functional.py | 16 +++ 4 files changed, 93 insertions(+), 100 deletions(-) create mode 100644 CHANGES/10300.feature.rst diff --git a/CHANGES/10300.feature.rst b/CHANGES/10300.feature.rst new file mode 100644 index 00000000000..3632c3d41a7 --- /dev/null +++ b/CHANGES/10300.feature.rst @@ -0,0 +1,2 @@ +Update :py:func:`~aiohttp.request` to make it accept ``_RequestOptions`` kwargs. +-- by :user:`Cycloctane`. diff --git a/aiohttp/client.py b/aiohttp/client.py index 942bfcfa04a..9a5946617e8 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -1375,104 +1375,77 @@ async def __aexit__( await self._session.close() -def request( - method: str, - url: StrOrURL, - *, - params: Query = None, - data: Any = None, - json: Any = None, - headers: Optional[LooseHeaders] = None, - skip_auto_headers: Optional[Iterable[str]] = None, - auth: Optional[BasicAuth] = None, - allow_redirects: bool = True, - max_redirects: int = 10, - compress: Union[str, bool] = False, - chunked: Optional[bool] = None, - expect100: bool = False, - raise_for_status: Optional[bool] = None, - read_until_eof: bool = True, - proxy: Optional[StrOrURL] = None, - proxy_auth: Optional[BasicAuth] = None, - timeout: Union[ClientTimeout, _SENTINEL] = sentinel, - cookies: Optional[LooseCookies] = None, - version: HttpVersion = http.HttpVersion11, - connector: Optional[BaseConnector] = None, - read_bufsize: Optional[int] = None, - max_line_size: int = 8190, - max_field_size: int = 8190, -) -> _SessionRequestContextManager: - """Constructs and sends a request. - - Returns response object. - method - HTTP method - url - request url - params - (optional) Dictionary or bytes to be sent in the query - string of the new request - data - (optional) Dictionary, bytes, or file-like object to - send in the body of the request - json - (optional) Any json compatible python object - headers - (optional) Dictionary of HTTP Headers to send with - the request - cookies - (optional) Dict object to send with the request - auth - (optional) BasicAuth named tuple represent HTTP Basic Auth - auth - aiohttp.helpers.BasicAuth - allow_redirects - (optional) If set to False, do not follow - redirects - version - Request HTTP version. - compress - Set to True if request has to be compressed - with deflate encoding. - chunked - Set to chunk size for chunked transfer encoding. - expect100 - Expect 100-continue response from server. - connector - BaseConnector sub-class instance to support - connection pooling. - read_until_eof - Read response until eof if response - does not have Content-Length header. - loop - Optional event loop. - timeout - Optional ClientTimeout settings structure, 5min - total timeout by default. - Usage:: - >>> import aiohttp - >>> async with aiohttp.request('GET', 'http://python.org/') as resp: - ... print(resp) - ... data = await resp.read() - - """ - connector_owner = False - if connector is None: - connector_owner = True - connector = TCPConnector(force_close=True) - - session = ClientSession( - cookies=cookies, - version=version, - timeout=timeout, - connector=connector, - connector_owner=connector_owner, - ) +if sys.version_info >= (3, 11) and TYPE_CHECKING: - return _SessionRequestContextManager( - session._request( - method, - url, - params=params, - data=data, - json=json, - headers=headers, - skip_auto_headers=skip_auto_headers, - auth=auth, - allow_redirects=allow_redirects, - max_redirects=max_redirects, - compress=compress, - chunked=chunked, - expect100=expect100, - raise_for_status=raise_for_status, - read_until_eof=read_until_eof, - proxy=proxy, - proxy_auth=proxy_auth, - read_bufsize=read_bufsize, - max_line_size=max_line_size, - max_field_size=max_field_size, - ), - session, - ) + def request( + method: str, + url: StrOrURL, + *, + version: HttpVersion = http.HttpVersion11, + connector: Optional[BaseConnector] = None, + **kwargs: Unpack[_RequestOptions], + ) -> _SessionRequestContextManager: ... + +else: + + def request( + method: str, + url: StrOrURL, + *, + version: HttpVersion = http.HttpVersion11, + connector: Optional[BaseConnector] = None, + **kwargs: Any, + ) -> _SessionRequestContextManager: + """Constructs and sends a request. + + Returns response object. + method - HTTP method + url - request url + params - (optional) Dictionary or bytes to be sent in the query + string of the new request + data - (optional) Dictionary, bytes, or file-like object to + send in the body of the request + json - (optional) Any json compatible python object + headers - (optional) Dictionary of HTTP Headers to send with + the request + cookies - (optional) Dict object to send with the request + auth - (optional) BasicAuth named tuple represent HTTP Basic Auth + auth - aiohttp.helpers.BasicAuth + allow_redirects - (optional) If set to False, do not follow + redirects + version - Request HTTP version. + compress - Set to True if request has to be compressed + with deflate encoding. + chunked - Set to chunk size for chunked transfer encoding. + expect100 - Expect 100-continue response from server. + connector - BaseConnector sub-class instance to support + connection pooling. + read_until_eof - Read response until eof if response + does not have Content-Length header. + loop - Optional event loop. + timeout - Optional ClientTimeout settings structure, 5min + total timeout by default. + Usage:: + >>> import aiohttp + >>> async with aiohttp.request('GET', 'http://python.org/') as resp: + ... print(resp) + ... data = await resp.read() + + """ + connector_owner = False + if connector is None: + connector_owner = True + connector = TCPConnector(force_close=True) + + session = ClientSession( + cookies=kwargs.pop("cookies", None), + version=version, + timeout=kwargs.pop("timeout", sentinel), + connector=connector, + connector_owner=connector_owner, + ) + + return _SessionRequestContextManager( + session._request(method, url, **kwargs), + session, + ) diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt index 33d6c7ecf2c..121d49aab20 100644 --- a/docs/spelling_wordlist.txt +++ b/docs/spelling_wordlist.txt @@ -13,6 +13,7 @@ app app’s apps arg +args Arsenic async asyncio @@ -170,6 +171,7 @@ keepaliving kib KiB kwarg +kwargs latin lifecycle linux diff --git a/tests/test_client_functional.py b/tests/test_client_functional.py index 77d74b441d5..6c8bbca634f 100644 --- a/tests/test_client_functional.py +++ b/tests/test_client_functional.py @@ -3448,6 +3448,22 @@ async def handler(request: web.Request) -> web.Response: await server.close() +async def test_aiohttp_request_ssl( + aiohttp_server: AiohttpServer, + ssl_ctx: ssl.SSLContext, + client_ssl_ctx: ssl.SSLContext, +) -> None: + async def handler(request: web.Request) -> web.Response: + return web.Response() + + app = web.Application() + app.router.add_get("/", handler) + server = await aiohttp_server(app, ssl=ssl_ctx) + + async with aiohttp.request("GET", server.make_url("/"), ssl=client_ssl_ctx) as resp: + assert resp.status == 200 + + async def test_yield_from_in_session_request(aiohttp_client: AiohttpClient) -> None: # a test for backward compatibility with yield from syntax async def handler(request: web.Request) -> web.Response: