From f9c86b48a0f7a6a39ba3817e5393b352fe417511 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 07:11:07 +0100 Subject: [PATCH 1/7] try fixing AioHTTPTestCase for 3.11 --- aiohttp/test_utils.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py index 82956986b9d..545baec5fb2 100644 --- a/aiohttp/test_utils.py +++ b/aiohttp/test_utils.py @@ -429,13 +429,9 @@ def get_app(self) -> Application: """ raise RuntimeError("Did you forget to define get_application()?") - def setUp(self) -> None: - try: - self.loop = asyncio.get_running_loop() - except RuntimeError: - self.loop = asyncio.get_event_loop_policy().get_event_loop() - - self.loop.run_until_complete(self.setUpAsync()) + async def asyncSetUp(self): + self.loop = asyncio.get_running_loop() + return await self.setUpAsync() async def setUpAsync(self) -> None: self.app = await self.get_application() @@ -444,8 +440,8 @@ async def setUpAsync(self) -> None: await self.client.start_server() - def tearDown(self) -> None: - self.loop.run_until_complete(self.tearDownAsync()) + async def asyncTearDown(self) -> None: + return await self.tearDownAsync() async def tearDownAsync(self) -> None: await self.client.close() From 355dc8e7bb0d041408261eba0b2719e357057699 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 07:12:51 +0100 Subject: [PATCH 2/7] Update aiohttp/test_utils.py --- aiohttp/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py index 545baec5fb2..7b266095a9e 100644 --- a/aiohttp/test_utils.py +++ b/aiohttp/test_utils.py @@ -429,7 +429,7 @@ def get_app(self) -> Application: """ raise RuntimeError("Did you forget to define get_application()?") - async def asyncSetUp(self): + async def asyncSetUp(self) -> None: self.loop = asyncio.get_running_loop() return await self.setUpAsync() From 37fa089f3ed7b3d64e3280be57490aa41cf85459 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 07:27:08 +0100 Subject: [PATCH 3/7] add the setUp/tearDown code back to 3.7 --- aiohttp/test_utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aiohttp/test_utils.py b/aiohttp/test_utils.py index 7b266095a9e..e0aacbb68fc 100644 --- a/aiohttp/test_utils.py +++ b/aiohttp/test_utils.py @@ -429,6 +429,10 @@ def get_app(self) -> Application: """ raise RuntimeError("Did you forget to define get_application()?") + def setUp(self) -> None: + if not PY_38: + asyncio.get_event_loop().run_until_complete(self.asyncSetUp()) + async def asyncSetUp(self) -> None: self.loop = asyncio.get_running_loop() return await self.setUpAsync() @@ -440,6 +444,10 @@ async def setUpAsync(self) -> None: await self.client.start_server() + def tearDown(self) -> None: + if not PY_38: + self.loop.run_until_complete(self.asyncTearDown()) + async def asyncTearDown(self) -> None: return await self.tearDownAsync() From e5789af1448b6022b52c6968e76e772cb6409212 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 09:34:38 +0100 Subject: [PATCH 4/7] disambiguate asyncio.TimeoutError from OSError in 3.11 asyncio.TimeoutError became an OSError --- aiohttp/client.py | 2 ++ aiohttp/client_reqrep.py | 2 ++ aiohttp/connector.py | 10 ++++++++++ 3 files changed, 14 insertions(+) diff --git a/aiohttp/client.py b/aiohttp/client.py index d05689ca6b7..05ef05bb368 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -531,6 +531,8 @@ async def _request( raise except ClientError: raise + except asyncio.TimeoutError: + raise except OSError as exc: raise ClientOSError(*exc.args) from exc diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 733cd48f63c..689d4b7563f 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -536,6 +536,8 @@ async def write_bytes( await writer.write(chunk) # type: ignore[arg-type] await writer.write_eof() + except asyncio.TimeoutError: + raise except OSError as exc: new_exc = ClientOSError( exc.errno, "Can not write request body for %s" % self.url diff --git a/aiohttp/connector.py b/aiohttp/connector.py index 86399b84272..cdbc7c3261b 100644 --- a/aiohttp/connector.py +++ b/aiohttp/connector.py @@ -969,6 +969,8 @@ async def _wrap_create_connection( raise ClientConnectorCertificateError(req.connection_key, exc) from exc except ssl_errors as exc: raise ClientConnectorSSLError(req.connection_key, exc) from exc + except asyncio.TimeoutError: + raise except OSError as exc: raise client_error(req.connection_key, exc) from exc @@ -1048,6 +1050,8 @@ async def _start_tls_connection( raise ClientConnectorCertificateError(req.connection_key, exc) from exc except ssl_errors as exc: raise ClientConnectorSSLError(req.connection_key, exc) from exc + except asyncio.TimeoutError: + raise except OSError as exc: raise client_error(req.connection_key, exc) from exc except TypeError as type_err: @@ -1099,6 +1103,8 @@ def drop_exception(fut: "asyncio.Future[List[Dict[str, Any]]]") -> None: host_resolved.add_done_callback(drop_exception) raise + except asyncio.TimeoutError: + raise except OSError as exc: # in case of proxy it is not ClientProxyConnectionError # it is problem of resolving proxy ip itself @@ -1292,6 +1298,8 @@ async def _create_connection( _, proto = await self._loop.create_unix_connection( self._factory, self._path ) + except asyncio.TimeoutError: + raise except OSError as exc: raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc @@ -1357,6 +1365,8 @@ async def _create_connection( await asyncio.sleep(0) # other option is to manually set transport like # `proto.transport = trans` + except asyncio.TimeoutError: + raise except OSError as exc: raise ClientConnectorError(req.connection_key, exc) from exc From 74340cb9482f0ca452ec67668f141a460b011a2f Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 09:58:22 +0100 Subject: [PATCH 5/7] wrap real OSError asyncio.TimeoutErrors in a ClientOSError --- aiohttp/client.py | 4 ++-- aiohttp/client_reqrep.py | 17 +++++++++-------- aiohttp/connector.py | 20 ++++++++++---------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/aiohttp/client.py b/aiohttp/client.py index 05ef05bb368..a97190d078a 100644 --- a/aiohttp/client.py +++ b/aiohttp/client.py @@ -531,9 +531,9 @@ async def _request( raise except ClientError: raise - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise raise ClientOSError(*exc.args) from exc self._cookie_jar.update_cookies(resp.cookies, resp.url) diff --git a/aiohttp/client_reqrep.py b/aiohttp/client_reqrep.py index 689d4b7563f..9478e8d36c5 100644 --- a/aiohttp/client_reqrep.py +++ b/aiohttp/client_reqrep.py @@ -536,15 +536,16 @@ async def write_bytes( await writer.write(chunk) # type: ignore[arg-type] await writer.write_eof() - except asyncio.TimeoutError: - raise except OSError as exc: - new_exc = ClientOSError( - exc.errno, "Can not write request body for %s" % self.url - ) - new_exc.__context__ = exc - new_exc.__cause__ = exc - protocol.set_exception(new_exc) + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + protocol.set_exception(exc) + else: + new_exc = ClientOSError( + exc.errno, "Can not write request body for %s" % self.url + ) + new_exc.__context__ = exc + new_exc.__cause__ = exc + protocol.set_exception(new_exc) except asyncio.CancelledError as exc: if not conn.closed: protocol.set_exception(exc) diff --git a/aiohttp/connector.py b/aiohttp/connector.py index cdbc7c3261b..7dbbf4f2d80 100644 --- a/aiohttp/connector.py +++ b/aiohttp/connector.py @@ -969,9 +969,9 @@ async def _wrap_create_connection( raise ClientConnectorCertificateError(req.connection_key, exc) from exc except ssl_errors as exc: raise ClientConnectorSSLError(req.connection_key, exc) from exc - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise raise client_error(req.connection_key, exc) from exc def _warn_about_tls_in_tls( @@ -1050,9 +1050,9 @@ async def _start_tls_connection( raise ClientConnectorCertificateError(req.connection_key, exc) from exc except ssl_errors as exc: raise ClientConnectorSSLError(req.connection_key, exc) from exc - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise raise client_error(req.connection_key, exc) from exc except TypeError as type_err: # Example cause looks like this: @@ -1103,9 +1103,9 @@ def drop_exception(fut: "asyncio.Future[List[Dict[str, Any]]]") -> None: host_resolved.add_done_callback(drop_exception) raise - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise # in case of proxy it is not ClientProxyConnectionError # it is problem of resolving proxy ip itself raise ClientConnectorError(req.connection_key, exc) from exc @@ -1298,9 +1298,9 @@ async def _create_connection( _, proto = await self._loop.create_unix_connection( self._factory, self._path ) - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise raise UnixClientConnectorError(self.path, req.connection_key, exc) from exc return cast(ResponseHandler, proto) @@ -1365,9 +1365,9 @@ async def _create_connection( await asyncio.sleep(0) # other option is to manually set transport like # `proto.transport = trans` - except asyncio.TimeoutError: - raise except OSError as exc: + if exc.errno is None and isinstance(exc, asyncio.TimeoutError): + raise raise ClientConnectorError(req.connection_key, exc) from exc return cast(ResponseHandler, proto) From a776ee3c7f1450eee2a2a466617488e7c5cce97d Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Tue, 9 Aug 2022 11:59:57 +0100 Subject: [PATCH 6/7] add changelog --- CHANGES/6757.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/6757.misc diff --git a/CHANGES/6757.misc b/CHANGES/6757.misc new file mode 100644 index 00000000000..81163a374dc --- /dev/null +++ b/CHANGES/6757.misc @@ -0,0 +1 @@ +work around the changes in 3.11, eg asyncio.TimeoutError is an OSError, and IsolatedAsyncioTestCase calls set_event_loop differently From 37b892c38deddac030bcf49a49339535edf77824 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Mon, 22 Aug 2022 04:34:07 +0200 Subject: [PATCH 7/7] Apply formatting to the change note --- CHANGES/6757.misc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES/6757.misc b/CHANGES/6757.misc index 81163a374dc..986e3feb95f 100644 --- a/CHANGES/6757.misc +++ b/CHANGES/6757.misc @@ -1 +1,3 @@ -work around the changes in 3.11, eg asyncio.TimeoutError is an OSError, and IsolatedAsyncioTestCase calls set_event_loop differently +Work around the changes in 3.11, e.g. :py:class:`~asyncio.TimeoutError` is an :py:class:`OSError`, +and :py:class:`~unittest.IsolatedAsyncioTestCase` calls :py:function:`~asyncio.set_event_loop` +differently -- by :user:`graingert`.