diff --git a/.evergreen/generated_configs/variants.yml b/.evergreen/generated_configs/variants.yml index 5e769173f9..dbfec82f93 100644 --- a/.evergreen/generated_configs/variants.yml +++ b/.evergreen/generated_configs/variants.yml @@ -319,14 +319,6 @@ buildvariants: tags: [] # Green framework tests - - name: green-eventlet-rhel8 - tasks: - - name: .test-standard .python-3.9 .sync - display_name: Green Eventlet RHEL8 - run_on: - - rhel87-small - expansions: - GREEN_FRAMEWORK: eventlet - name: green-gevent-rhel8 tasks: - name: .test-standard .sync diff --git a/.evergreen/scripts/generate_config.py b/.evergreen/scripts/generate_config.py index a04a64d30a..7b17b127f4 100644 --- a/.evergreen/scripts/generate_config.py +++ b/.evergreen/scripts/generate_config.py @@ -300,12 +300,8 @@ def create_stable_api_variants(): def create_green_framework_variants(): variants = [] host = DEFAULT_HOST - for framework in ["eventlet", "gevent"]: + for framework in ["gevent"]: tasks = [".test-standard .sync"] - if framework == "eventlet": - # Eventlet has issues with dnspython > 2.0 and newer versions of CPython - # https://jira.mongodb.org/browse/PYTHON-5284 - tasks = [".test-standard .python-3.9 .sync"] expansions = dict(GREEN_FRAMEWORK=framework) display_name = get_variant_name(f"Green {framework.capitalize()}", host) variant = create_variant(tasks, display_name, host=host, expansions=expansions) diff --git a/.evergreen/scripts/run_tests.py b/.evergreen/scripts/run_tests.py index 3a1c15a41b..fd4fd13e5b 100644 --- a/.evergreen/scripts/run_tests.py +++ b/.evergreen/scripts/run_tests.py @@ -67,13 +67,7 @@ def handle_perf(start_time: datetime): def handle_green_framework() -> None: - if GREEN_FRAMEWORK == "eventlet": - import eventlet - - # https://github.com/eventlet/eventlet/issues/401 - eventlet.sleep() - eventlet.monkey_patch() - elif GREEN_FRAMEWORK == "gevent": + if GREEN_FRAMEWORK == "gevent": from gevent import monkey monkey.patch_all() diff --git a/.evergreen/scripts/utils.py b/.evergreen/scripts/utils.py index 8d1b466b6c..50894ff634 100644 --- a/.evergreen/scripts/utils.py +++ b/.evergreen/scripts/utils.py @@ -104,7 +104,7 @@ def get_test_options( parser.add_argument( "--green-framework", nargs=1, - choices=["eventlet", "gevent"], + choices=["gevent"], help="Optional green framework to test against.", ) parser.add_argument( diff --git a/doc/changelog.rst b/doc/changelog.rst index 7270043d41..6dcb80497b 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -9,6 +9,8 @@ PyMongo 4.16 brings a number of changes including: - Removed invalid documents from :class:`bson.errors.InvalidDocument` error messages as doing so may leak sensitive user data. Instead, invalid documents are stored in :attr:`bson.errors.InvalidDocument.document`. +- Removed support for Eventlet. + Eventlet is actively being sunset by its maintainers and has compatibility issues with PyMongo's dnspython dependency. Changes in Version 4.15.1 (2025/09/16) -------------------------------------- diff --git a/pymongo/asynchronous/pool.py b/pymongo/asynchronous/pool.py index 196ec9040f..f521091e3c 100644 --- a/pymongo/asynchronous/pool.py +++ b/pymongo/asynchronous/pool.py @@ -628,7 +628,7 @@ async def _raise_connection_failure(self, error: BaseException) -> NoReturn: # signals and throws KeyboardInterrupt into the current frame on the # main thread. # - # But in Gevent and Eventlet, the polling mechanism (epoll, kqueue, + # But in Gevent, the polling mechanism (epoll, kqueue, # ..) is called in Python code, which experiences the signal as a # KeyboardInterrupt from the start, rather than as an initial # socket.error, so we catch that, close the socket, and reraise it. diff --git a/pymongo/pool_shared.py b/pymongo/pool_shared.py index ac562af542..8db26ccead 100644 --- a/pymongo/pool_shared.py +++ b/pymongo/pool_shared.py @@ -138,13 +138,11 @@ def _raise_connection_failure( msg = msg_prefix + msg if "configured timeouts" not in msg: msg += format_timeout_details(timeout_details) - if isinstance(error, socket.timeout): - raise NetworkTimeout(msg) from error - elif isinstance(error, SSLErrors) and "timed out" in str(error): - # Eventlet does not distinguish TLS network timeouts from other - # SSLErrors (https://github.com/eventlet/eventlet/issues/692). - # Luckily, we can work around this limitation because the phrase - # 'timed out' appears in all the timeout related SSLErrors raised. + if ( + isinstance(error, socket.timeout) + or isinstance(error, SSLErrors) + and "timed out" in str(error) + ): raise NetworkTimeout(msg) from error else: raise AutoReconnect(msg) from error diff --git a/pymongo/synchronous/pool.py b/pymongo/synchronous/pool.py index f7f6a26c68..66258fda18 100644 --- a/pymongo/synchronous/pool.py +++ b/pymongo/synchronous/pool.py @@ -626,7 +626,7 @@ def _raise_connection_failure(self, error: BaseException) -> NoReturn: # signals and throws KeyboardInterrupt into the current frame on the # main thread. # - # But in Gevent and Eventlet, the polling mechanism (epoll, kqueue, + # But in Gevent, the polling mechanism (epoll, kqueue, # ..) is called in Python code, which experiences the signal as a # KeyboardInterrupt from the start, rather than as an initial # socket.error, so we catch that, close the socket, and reraise it. diff --git a/pyproject.toml b/pyproject.toml index 53fbfc8c1d..2130c61a96 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,6 @@ dev = [ pip = ["pip"] # TODO: PYTHON-5464 gevent = ["gevent", "cffi>=2.0.0b1;python_version=='3.14'"] -eventlet = ["eventlet"] coverage = [ "pytest-cov", "coverage>=5,<=7.10.6" @@ -113,15 +112,12 @@ filterwarnings = [ "module:.*WindowsSelectorEventLoopPolicy:DeprecationWarning", "module:.*et_event_loop_policy:DeprecationWarning", # TODO: Remove as part of PYTHON-3923. - "module:unclosed