Skip to content

Commit

Permalink
Make creating RequestInfo backwards compatible with 3.10
Browse files Browse the repository at this point in the history
It was unexpected that this object was being created directly
outside of aiohttp internals. While it looks like its only
used for mocking downstream, we can accomodate that by subclassing
the NamedTuple and providing a `__new__` while keeping the faster
`tuple.__new__` internally.

fixes #9866
  • Loading branch information
bdraco committed Nov 14, 2024
1 parent 4adb061 commit 1efc603
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
17 changes: 16 additions & 1 deletion aiohttp/client_reqrep.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from .formdata import FormData
from .hdrs import CONTENT_TYPE
from .helpers import (
_SENTINEL,
BaseTimerContext,
BasicAuth,
HeadersMixin,
Expand Down Expand Up @@ -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,
Expand Down
28 changes: 28 additions & 0 deletions tests/test_client_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

0 comments on commit 1efc603

Please sign in to comment.