Skip to content

Commit dc61477

Browse files
authored
[PR #10030/cdc01cd backport][3.11] Reduce initialization overhead in ClientResponse (#10031)
1 parent c8426a8 commit dc61477

File tree

3 files changed

+37
-16
lines changed

3 files changed

+37
-16
lines changed

CHANGES/10030.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved performance of creating :class:`aiohttp.ClientResponse` objects -- by :user:`bdraco`.

aiohttp/client_reqrep.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -819,18 +819,25 @@ class ClientResponse(HeadersMixin):
819819
status: int = None # type: ignore[assignment] # Status-Code
820820
reason: Optional[str] = None # Reason-Phrase
821821

822-
content: StreamReader = None # type: ignore[assignment] # Payload stream
822+
content: StreamReader = None # type: ignore[assignment] # Payload stream
823+
_body: Optional[bytes] = None
823824
_headers: CIMultiDictProxy[str] = None # type: ignore[assignment]
825+
_history: Tuple["ClientResponse", ...] = ()
824826
_raw_headers: RawHeaders = None # type: ignore[assignment]
825827

826-
_connection = None # current connection
828+
_connection: Optional["Connection"] = None # current connection
829+
_continue: Optional["asyncio.Future[bool]"] = None
827830
_source_traceback: Optional[traceback.StackSummary] = None
831+
_session: Optional["ClientSession"] = None
828832
# set up by ClientRequest after ClientResponse object creation
829833
# post-init stage allows to not change ctor signature
830834
_closed = True # to allow __del__ for non-initialized properly response
831835
_released = False
832836
_in_context = False
833-
__writer = None
837+
838+
_resolve_charset: Callable[["ClientResponse", bytes], str] = lambda *_: "utf-8"
839+
840+
__writer: Optional["asyncio.Task[None]"] = None
834841

835842
def __init__(
836843
self,
@@ -845,34 +852,29 @@ def __init__(
845852
loop: asyncio.AbstractEventLoop,
846853
session: "ClientSession",
847854
) -> None:
848-
assert isinstance(url, URL)
855+
# URL forbids subclasses, so a simple type check is enough.
856+
assert type(url) is URL
849857

850858
self.method = method
851859
self.cookies = SimpleCookie()
852860

853861
self._real_url = url
854862
self._url = url.with_fragment(None) if url.raw_fragment else url
855-
self._body: Optional[bytes] = None
856863
if writer is not None:
857864
self._writer = writer
858-
self._continue = continue100 # None by default
859-
self._closed = True
860-
self._history: Tuple[ClientResponse, ...] = ()
865+
if continue100 is not None:
866+
self._continue = continue100
861867
self._request_info = request_info
862868
self._timer = timer if timer is not None else TimerNoop()
863869
self._cache: Dict[str, Any] = {}
864870
self._traces = traces
865871
self._loop = loop
866-
# store a reference to session #1985
867-
self._session: Optional[ClientSession] = session
868872
# Save reference to _resolve_charset, so that get_encoding() will still
869873
# work after the response has finished reading the body.
870-
if session is None:
871-
# TODO: Fix session=None in tests (see ClientRequest.__init__).
872-
self._resolve_charset: Callable[["ClientResponse", bytes], str] = (
873-
lambda *_: "utf-8"
874-
)
875-
else:
874+
# TODO: Fix session=None in tests (see ClientRequest.__init__).
875+
if session is not None:
876+
# store a reference to session #1985
877+
self._session = session
876878
self._resolve_charset = session._resolve_charset
877879
if loop.get_debug():
878880
self._source_traceback = traceback.extract_stack(sys._getframe(1))

tests/test_client_response.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,24 @@ def test_content_disposition_no_header() -> None:
981981
assert response.content_disposition is None
982982

983983

984+
def test_default_encoding_is_utf8() -> None:
985+
response = ClientResponse(
986+
"get",
987+
URL("http://def-cl-resp.org"),
988+
request_info=mock.Mock(),
989+
writer=WriterMock(),
990+
continue100=None,
991+
timer=TimerNoop(),
992+
traces=[],
993+
loop=mock.Mock(),
994+
session=None, # type: ignore[arg-type]
995+
)
996+
response._headers = CIMultiDictProxy(CIMultiDict({}))
997+
response._body = b""
998+
999+
assert response.get_encoding() == "utf-8"
1000+
1001+
9841002
def test_response_request_info() -> None:
9851003
url = "http://def-cl-resp.org"
9861004
headers = {"Content-Type": "application/json;charset=cp1251"}

0 commit comments

Comments
 (0)