From cb89061627c15f4d2ee52712433efb3a5fdbb2d4 Mon Sep 17 00:00:00 2001 From: Noah Stapp Date: Fri, 26 Jul 2024 09:49:28 -0700 Subject: [PATCH] PYTHON-4537 - Use selector asyncio loop on windows tests (#1748) --- pymongo/asynchronous/periodic_executor.py | 12 +++++++++++- pymongo/synchronous/periodic_executor.py | 12 +++++++++++- test/__init__.py | 10 ++++++++++ test/asynchronous/__init__.py | 10 ++++++++++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pymongo/asynchronous/periodic_executor.py b/pymongo/asynchronous/periodic_executor.py index 337d10f13..f3d2fddba 100644 --- a/pymongo/asynchronous/periodic_executor.py +++ b/pymongo/asynchronous/periodic_executor.py @@ -65,7 +65,17 @@ class PeriodicExecutor: return f"<{self.__class__.__name__}(name={self._name}) object at 0x{id(self):x}>" def _run_async(self) -> None: - asyncio.run(self._run()) # type: ignore[func-returns-value] + # The default asyncio loop implementation on Windows + # has issues with sharing sockets across loops (https://github.com/python/cpython/issues/122240) + # We explicitly use a different loop implementation here to prevent that issue + if sys.platform == "win32": + loop = asyncio.SelectorEventLoop() + try: + loop.run_until_complete(self._run()) # type: ignore[func-returns-value] + finally: + loop.close() + else: + asyncio.run(self._run()) # type: ignore[func-returns-value] def open(self) -> None: """Start. Multiple calls have no effect. diff --git a/pymongo/synchronous/periodic_executor.py b/pymongo/synchronous/periodic_executor.py index 43125016b..525268b14 100644 --- a/pymongo/synchronous/periodic_executor.py +++ b/pymongo/synchronous/periodic_executor.py @@ -65,7 +65,17 @@ class PeriodicExecutor: return f"<{self.__class__.__name__}(name={self._name}) object at 0x{id(self):x}>" def _run_async(self) -> None: - asyncio.run(self._run()) # type: ignore[func-returns-value] + # The default asyncio loop implementation on Windows + # has issues with sharing sockets across loops (https://github.com/python/cpython/issues/122240) + # We explicitly use a different loop implementation here to prevent that issue + if sys.platform == "win32": + loop = asyncio.SelectorEventLoop() + try: + loop.run_until_complete(self._run()) # type: ignore[func-returns-value] + finally: + loop.close() + else: + asyncio.run(self._run()) # type: ignore[func-returns-value] def open(self) -> None: """Start. Multiple calls have no effect. diff --git a/test/__init__.py b/test/__init__.py index b8bd18511..b603ae0a5 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -79,6 +79,16 @@ from pymongo.synchronous.mongo_client import MongoClient _IS_SYNC = True +# The default asyncio loop implementation on Windows +# has issues with sharing sockets across loops (https://github.com/python/cpython/issues/122240) +# We explicitly use a different loop implementation here to prevent that issue +if ( + not _IS_SYNC + and sys.platform == "win32" + and asyncio.get_event_loop_policy() == asyncio.WindowsProactorEventLoopPolicy +): + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type: ignore[attr-defined] + class ClientContext: client: MongoClient diff --git a/test/asynchronous/__init__.py b/test/asynchronous/__init__.py index 6f0785c4f..878ef81ba 100644 --- a/test/asynchronous/__init__.py +++ b/test/asynchronous/__init__.py @@ -79,6 +79,16 @@ from pymongo.ssl_support import HAVE_SSL, _ssl # type:ignore[attr-defined] _IS_SYNC = False +# The default asyncio loop implementation on Windows +# has issues with sharing sockets across loops (https://github.com/python/cpython/issues/122240) +# We explicitly use a different loop implementation here to prevent that issue +if ( + not _IS_SYNC + and sys.platform == "win32" + and asyncio.get_event_loop_policy() == asyncio.WindowsProactorEventLoopPolicy +): + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type: ignore[attr-defined] + class AsyncClientContext: client: AsyncMongoClient