From 24dfd80c6415955d4e47accb214ebaceec393998 Mon Sep 17 00:00:00 2001 From: Alex Carney Date: Fri, 19 May 2023 20:18:18 +0100 Subject: [PATCH] Ensure that `pygls.Server` uses the event loop it is given Before this commit `pygls` would override the event loop for the current thread even when given an existing loop to use. Now `pygls` will rely on `asyncio.new_event_loop` to create the appropriate event loop for the platform and only call it when `loop=None` This commit also introduces the `_own_loop` flag which is used to make sure `pygls` does not close an event loop it does not own. --- CHANGELOG.md | 8 ++++++++ pygls/server.py | 26 +++++++++++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95219edb..ee2cb409 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,18 @@ and this project adheres to [Semantic Versioning][semver]. ### Changed ### Fixed +- `pygls` no longer overrides the event loop for the current thread when given an explicit loop to use. ([#334]) + +[#334]: https://github.com/openlawlibrary/pygls/issues/334 + + ## [1.0.2] - May 15th, 2023 ### Changed - Update typeguard to 3.x ([#327]) +[#327]: https://github.com/openlawlibrary/pygls/issues/327 + + ### Fixed - Data files are no longer placed inside the wrong `site-packages` folder when installing `pygls` ([#232]) [#232]: https://github.com/openlawlibrary/pygls/issues/232 diff --git a/pygls/server.py b/pygls/server.py index 4fd6953b..1410c492 100644 --- a/pygls/server.py +++ b/pygls/server.py @@ -23,7 +23,7 @@ from threading import Event from typing import Any, Callable, List, Optional, TextIO, TypeVar, Union -from pygls import IS_WIN, IS_PYODIDE +from pygls import IS_PYODIDE from pygls.lsp import ConfigCallbackType, ShowDocumentCallbackType from pygls.exceptions import PyglsError, JsonRpcException, FeatureRequestError from lsprotocol.types import ( @@ -184,19 +184,14 @@ def __init__(self, protocol_cls, converter_factory, loop=None, max_workers=2, self._thread_pool_executor = None self.sync_kind = sync_kind - if IS_WIN: - asyncio.set_event_loop(asyncio.ProactorEventLoop()) - elif not IS_PYODIDE: - asyncio.set_event_loop(asyncio.SelectorEventLoop()) - - self.loop = loop or asyncio.new_event_loop() - - try: - if not IS_PYODIDE: - asyncio.get_child_watcher().attach_loop(self.loop) - except NotImplementedError: - pass + if loop is None: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + self._owns_loop = True + else: + self._owns_loop = False + self.loop = loop self.lsp = protocol_cls(self, converter_factory()) def shutdown(self): @@ -216,8 +211,9 @@ def shutdown(self): self._server.close() self.loop.run_until_complete(self._server.wait_closed()) - logger.info('Closing the event loop.') - self.loop.close() + if self._owns_loop and not self.loop.is_closed: + logger.info('Closing the event loop.') + self.loop.close() def start_io(self, stdin: Optional[TextIO] = None, stdout: Optional[TextIO] = None): """Starts IO server."""