Skip to content

Commit daaea93

Browse files
[PR #9873/c9698c8e backport][3.11] Make creating RequestInfo backwards compatible with 3.10 (#9874)
Co-authored-by: J. Nick Koston <[email protected]> fixes #9866
1 parent 72661bd commit daaea93

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

CHANGES/9873.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added a backward compatibility layer to `~aiohttp.RequestInfo` to allow creating these objects without a `real_url` -- by :user:`bdraco`.

aiohttp/client_reqrep.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from .compression_utils import HAS_BROTLI
4343
from .formdata import FormData
4444
from .helpers import (
45+
_SENTINEL,
4546
BaseTimerContext,
4647
BasicAuth,
4748
HeadersMixin,
@@ -103,13 +104,31 @@ class ContentDisposition:
103104
filename: Optional[str]
104105

105106

106-
class RequestInfo(NamedTuple):
107+
class _RequestInfo(NamedTuple):
107108
url: URL
108109
method: str
109110
headers: "CIMultiDictProxy[str]"
110111
real_url: URL
111112

112113

114+
class RequestInfo(_RequestInfo):
115+
116+
def __new__(
117+
cls,
118+
url: URL,
119+
method: str,
120+
headers: "CIMultiDictProxy[str]",
121+
real_url: URL = _SENTINEL, # type: ignore[assignment]
122+
) -> "RequestInfo":
123+
"""Create a new RequestInfo instance.
124+
125+
For backwards compatibility, the real_url parameter is optional.
126+
"""
127+
return tuple.__new__(
128+
cls, (url, method, headers, url if real_url is _SENTINEL else real_url)
129+
)
130+
131+
113132
class Fingerprint:
114133
HASHFUNC_BY_DIGESTLEN = {
115134
16: md5,
@@ -391,7 +410,9 @@ def port(self) -> Optional[int]:
391410
def request_info(self) -> RequestInfo:
392411
headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)
393412
# These are created on every request, so we use a NamedTuple
394-
# for performance reasons.
413+
# for performance reasons. We don't use the RequestInfo.__new__
414+
# method because it has a different signature which is provided
415+
# for backwards compatibility only.
395416
return tuple.__new__(
396417
RequestInfo, (self.url, self.method, headers, self.original_url)
397418
)

tests/test_client_request.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,3 +1492,46 @@ async def test_connection_key_without_proxy() -> None:
14921492
)
14931493
assert req.connection_key.proxy_headers_hash is None
14941494
await req.close()
1495+
1496+
1497+
def test_request_info_back_compat() -> None:
1498+
"""Test RequestInfo can be created without real_url."""
1499+
url = URL("http://example.com")
1500+
other_url = URL("http://example.org")
1501+
assert (
1502+
aiohttp.RequestInfo(
1503+
url=url, method="GET", headers=CIMultiDictProxy(CIMultiDict())
1504+
).real_url
1505+
is url
1506+
)
1507+
assert (
1508+
aiohttp.RequestInfo(url, "GET", CIMultiDictProxy(CIMultiDict())).real_url is url
1509+
)
1510+
assert (
1511+
aiohttp.RequestInfo(
1512+
url, "GET", CIMultiDictProxy(CIMultiDict()), real_url=url
1513+
).real_url
1514+
is url
1515+
)
1516+
assert (
1517+
aiohttp.RequestInfo(
1518+
url, "GET", CIMultiDictProxy(CIMultiDict()), real_url=other_url
1519+
).real_url
1520+
is other_url
1521+
)
1522+
1523+
1524+
def test_request_info_tuple_new() -> None:
1525+
"""Test RequestInfo must be created with real_url using tuple.__new__."""
1526+
url = URL("http://example.com")
1527+
with pytest.raises(IndexError):
1528+
tuple.__new__(
1529+
aiohttp.RequestInfo, (url, "GET", CIMultiDictProxy(CIMultiDict()))
1530+
).real_url
1531+
1532+
assert (
1533+
tuple.__new__(
1534+
aiohttp.RequestInfo, (url, "GET", CIMultiDictProxy(CIMultiDict()), url)
1535+
).real_url
1536+
is url
1537+
)

0 commit comments

Comments
 (0)