|
1 | 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | | -from copy import copy, deepcopy |
| 3 | +import weakref |
| 4 | +from copy import deepcopy |
4 | 5 | from itertools import chain |
5 | 6 | from typing import TYPE_CHECKING, Any |
6 | 7 | from urllib.parse import parse_qs |
@@ -65,13 +66,22 @@ def __init__( |
65 | 66 | """ |
66 | 67 | _assert_aiohttp() |
67 | 68 | self._config = client_config or AIOHTTPClientConfig() |
68 | | - # Disable transparent response decompression and advertise |
69 | | - # 'identity' to request uncompressed responses. |
70 | | - # TODO: add a functional test once the test client framework exists |
71 | | - self._session = _session or aiohttp.ClientSession( |
72 | | - auto_decompress=False, |
73 | | - headers={"Accept-Encoding": "identity"}, |
74 | | - ) |
| 69 | + if _session is not None: |
| 70 | + self._session = _session |
| 71 | + else: |
| 72 | + # Disable transparent response decompression and advertise |
| 73 | + # 'identity' to request uncompressed responses. |
| 74 | + # TODO: add a functional test once the test client framework exists |
| 75 | + self._session = aiohttp.ClientSession( |
| 76 | + auto_decompress=False, |
| 77 | + headers={"Accept-Encoding": "identity"}, |
| 78 | + ) |
| 79 | + # Close the connector on GC/interpreter exit so aiohttp doesn't |
| 80 | + # emit "Unclosed client session"/"Unclosed connector" warnings |
| 81 | + # when the client is never closed explicitly. |
| 82 | + self._finalizer = weakref.finalize( |
| 83 | + self, self._close_session, self._session |
| 84 | + ) |
75 | 85 |
|
76 | 86 | async def send( |
77 | 87 | self, |
@@ -143,5 +153,17 @@ async def _marshal_response( |
143 | 153 | def __deepcopy__(self, memo: Any) -> "AIOHTTPClient": |
144 | 154 | return AIOHTTPClient( |
145 | 155 | client_config=deepcopy(self._config), |
146 | | - _session=copy(self._session), |
| 156 | + _session=self._session, |
147 | 157 | ) |
| 158 | + |
| 159 | + @staticmethod |
| 160 | + def _close_session(session: "aiohttp.ClientSession") -> None: |
| 161 | + """Synchronously close a session's connector. |
| 162 | +
|
| 163 | + Runs from the :py:class:`weakref.finalize` hook, where there may be no |
| 164 | + running event loop, so we close the connector directly instead of |
| 165 | + awaiting ``session.close()``. |
| 166 | + """ |
| 167 | + connector = session.connector |
| 168 | + if connector is not None and not connector.closed: |
| 169 | + connector._close() # type: ignore[attr-defined] |
0 commit comments