Skip to content

Commit

Permalink
[PR #9873/c9698c8e backport][3.11] Make creating RequestInfo backwa…
Browse files Browse the repository at this point in the history
…rds compatible with 3.10 (#9874)

Co-authored-by: J. Nick Koston <[email protected]>
fixes #9866
  • Loading branch information
patchback[bot] authored Nov 14, 2024
1 parent 72661bd commit daaea93
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES/9873.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a backward compatibility layer to `~aiohttp.RequestInfo` to allow creating these objects without a `real_url` -- by :user:`bdraco`.
25 changes: 23 additions & 2 deletions aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from .compression_utils import HAS_BROTLI
from .formdata import FormData
from .helpers import (
_SENTINEL,
BaseTimerContext,
BasicAuth,
HeadersMixin,
Expand Down Expand Up @@ -103,13 +104,31 @@ 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, # type: ignore[assignment]
) -> "RequestInfo":
"""Create a new RequestInfo instance.
For backwards compatibility, the real_url parameter is optional.
"""
return tuple.__new__(
cls, (url, method, headers, url if real_url is _SENTINEL else real_url)
)


class Fingerprint:
HASHFUNC_BY_DIGESTLEN = {
16: md5,
Expand Down Expand Up @@ -391,7 +410,9 @@ def port(self) -> Optional[int]:
def request_info(self) -> RequestInfo:
headers: CIMultiDictProxy[str] = CIMultiDictProxy(self.headers)
# These are created on every request, so we use a NamedTuple
# for performance reasons.
# for performance reasons. We don't use the RequestInfo.__new__
# method because it has a different signature which is provided
# for backwards compatibility only.
return tuple.__new__(
RequestInfo, (self.url, self.method, headers, self.original_url)
)
Expand Down
43 changes: 43 additions & 0 deletions tests/test_client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,3 +1492,46 @@ 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=CIMultiDictProxy(CIMultiDict())
).real_url
is url
)
assert (
aiohttp.RequestInfo(url, "GET", CIMultiDictProxy(CIMultiDict())).real_url is url
)
assert (
aiohttp.RequestInfo(
url, "GET", CIMultiDictProxy(CIMultiDict()), real_url=url
).real_url
is url
)
assert (
aiohttp.RequestInfo(
url, "GET", CIMultiDictProxy(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", CIMultiDictProxy(CIMultiDict()))
).real_url

assert (
tuple.__new__(
aiohttp.RequestInfo, (url, "GET", CIMultiDictProxy(CIMultiDict()), url)
).real_url
is url
)

0 comments on commit daaea93

Please sign in to comment.