Skip to content

Commit

Permalink
Ensure that pygls.Server uses the event loop it is given
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alcarney committed May 19, 2023
1 parent f9023da commit 24dfd80
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 15 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 11 additions & 15 deletions pygls/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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):
Expand All @@ -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."""
Expand Down

0 comments on commit 24dfd80

Please sign in to comment.