diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 8e7ebbcbebe..472fa9421cd 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -43,6 +43,7 @@ from .formdata import FormData from .hdrs import CONTENT_TYPE from .helpers import ( + _SENTINEL, BaseTimerContext, BasicAuth, HeadersMixin, @@ -104,13 +105,27 @@ class ContentDisposition: filename: Optional[str] -class RequestInfo(NamedTuple): +class _RequestInfo(NamedTuple): url: URL method: str headers: "CIMultiDictProxy[str]" real_url: URL +class RequestInfo(_RequestInfo): + + def __new__( + cls, + url: URL, + method: str, + headers: "CIMultiDictProxy[str]", + real_url: URL = _SENTINEL, + ) -> "RequestInfo": + return tuple.__new__( + cls, (url, method, headers, url if real_url is _SENTINEL else real_url) + ) + + class Fingerprint: HASHFUNC_BY_DIGESTLEN = { 16: md5, diff --git a/tests/test_client_request.py b/tests/test_client_request.py index d20374ee163..9ce5b0117bf 100644 --- a/tests/test_client_request.py +++ b/tests/test_client_request.py @@ -1544,3 +1544,31 @@ async def test_connection_key_without_proxy() -> None: ) assert req.connection_key.proxy_headers_hash is None await req.close() + + +def test_request_info_back_compat() -> None: + """Test RequestInfo can be created without real_url.""" + url = URL("http://example.com") + other_url = URL("http://example.org") + assert ( + aiohttp.RequestInfo(url=url, method="GET", headers=CIMultiDict()).real_url + is url + ) + assert aiohttp.RequestInfo(url, "GET", CIMultiDict()).real_url is url + assert aiohttp.RequestInfo(url, "GET", CIMultiDict(), real_url=url).real_url is url + assert ( + aiohttp.RequestInfo(url, "GET", CIMultiDict(), real_url=other_url).real_url + is other_url + ) + + +def test_request_info_tuple_new() -> None: + """Test RequestInfo must be created with real_url using tuple.__new__.""" + url = URL("http://example.com") + with pytest.raises(IndexError): + tuple.__new__(aiohttp.RequestInfo, (url, "GET", CIMultiDict())).real_url + + assert ( + tuple.__new__(aiohttp.RequestInfo, (url, "GET", CIMultiDict(), url)).real_url + is url + )