Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to pygls v2.0a2 #188

Merged
merged 6 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Client Capability Index

capabilities/*

Inspired by `caniuse.com <https://canisue.com>`__ this provides information on which clients support which features of the `LSP Specification <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/>`__.
Inspired by `caniuse.com <https://caniuse.com>`__ this provides information on which clients support which features of the `LSP Specification <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/>`__.

.. grid:: 2
:gutter: 2
Expand Down
3 changes: 2 additions & 1 deletion docs/pytest-lsp/howto/testing-json-rpc-servers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ As an example we'll reuse some of the `pygls`_ internals to write a simple JSON-

- client to server request ``math/add``, returns the sum of two numbers ``a`` and ``b``
- client to server request ``math/sub``, returns the difference of two numbers ``a`` and ``b``
- client to server notification ``server/exit`` that instructs the server to exit
- server to client notification ``log/message``, allows the server to send debug messages to the client.

.. note::
Expand Down Expand Up @@ -40,7 +41,7 @@ Once you have your factory function defined you can pass it to the :class:`~pyte
.. literalinclude:: ../../../lib/pytest-lsp/tests/examples/generic-rpc/t_server.py
:language: python
:start-at: @pytest_lsp.fixture(
:end-at: # Teardown code
:end-at: rpc_client.protocol.notify

Writing Test Cases
------------------
Expand Down
1 change: 1 addition & 0 deletions lib/pytest-lsp/changes/188.misc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Update `pygls` to `v2.0a2`
2 changes: 1 addition & 1 deletion lib/pytest-lsp/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ classifiers = [
]
dependencies = [
"packaging",
"pygls>=2.0.0a1",
"pygls>=2.0.0a2",
"pytest",
"pytest-asyncio>=0.24",
]
Expand Down
20 changes: 6 additions & 14 deletions lib/pytest-lsp/pytest_lsp/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,6 @@ async def server_exit(self, server: asyncio.subprocess.Process):
if self._stop_event.is_set():
return

# TODO: Should the upstream base client be doing this?
# Cancel any pending futures.
reason = f"Server process {server.pid} exited with code: {server.returncode}"

for id_, fut in self.protocol._request_futures.items():
if not fut.done():
fut.set_exception(RuntimeError(reason))
logger.debug("Cancelled pending request '%s': %s", id_, reason)

def report_server_error(
self, error: Exception, source: PyglsError | JsonRpcException
):
Expand All @@ -117,12 +108,13 @@ def report_server_error(
tb = "".join(traceback.format_exc())

message = f"{source.__name__}: {error}\n{tb}" # type: ignore
for id_, fut in self.protocol._request_futures.items():
if not fut.done():
fut.set_exception(RuntimeError(message))
logger.debug("Cancelled pending request '%s': %s", id_, message)

loop = asyncio.get_running_loop()
loop.call_soon(cancel_all_tasks, message)

if self._stop_event:
self._stop_event.set()
if self._server:
self._server.terminate()

def get_configuration(
self, *, section: str | None = None, scope_uri: str | None = None
Expand Down
7 changes: 7 additions & 0 deletions lib/pytest-lsp/tests/examples/generic-rpc/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sys

from pygls.protocol import JsonRPCProtocol, default_converter
from pygls.server import JsonRPCServer

Expand Down Expand Up @@ -28,5 +30,10 @@ def subtraction(ls: JsonRPCServer, params):
return dict(total=b - a)


@server.feature("server/exit")
def server_exit(ls: JsonRPCServer, params):
sys.exit(0)


if __name__ == "__main__":
server.start_io()
3 changes: 2 additions & 1 deletion lib/pytest-lsp/tests/examples/generic-rpc/t_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ async def client(rpc_client: JsonRPCClient):

yield

# Teardown code here (if any)
# Teardown code here
rpc_client.protocol.notify("server/exit", {})


@pytest.mark.asyncio
Expand Down
6 changes: 5 additions & 1 deletion lib/pytest-lsp/tests/servers/invalid_json.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# A server that returns a message that cannot be parsed as JSON.
import json
import sys

from lsprotocol import types
from pygls.io_ import StdoutWriter
from pygls.lsp.server import LanguageServer

server = LanguageServer(name="completion-exit-server", version="v1.0")
Expand All @@ -20,12 +22,14 @@ def bad_send_data(data):
f"Content-Type: {self.CONTENT_TYPE}; charset={self.CHARSET}\r\n\r\n"
).encode(self.CHARSET)

self.transport.write(header + body)
self.writer.write(header + body)


@server.feature(types.TEXT_DOCUMENT_COMPLETION)
def on_complete(server: LanguageServer, params: types.CompletionParams):
server.protocol._send_data = bad_send_data
server.protocol.set_writer(StdoutWriter(sys.stdout.buffer))

return [types.CompletionItem(label="item-one")]


Expand Down
2 changes: 1 addition & 1 deletion lib/pytest-lsp/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def test_getting_started_fail(pytester: pytest.Pytester):
results = pytester.runpytest()
results.assert_outcomes(errors=1)

message = r"E\s+RuntimeError: Server process \d+ exited with code: 0"
message = r"E\s+RuntimeError: Server process \d+ exited with return code: 0"
results.stdout.re_match_lines(message)


Expand Down
14 changes: 5 additions & 9 deletions lib/pytest-lsp/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ async def test_capabilities(client):

results.assert_outcomes(errors=1)

message = r"E\s+RuntimeError: Server process \d+ exited with code: 0"
message = r"E\s+RuntimeError: Server process \d+ exited with return code: 0"
results.stdout.re_match_lines(message)


Expand Down Expand Up @@ -162,7 +162,7 @@ async def test_capabilities(client):

results.assert_outcomes(failed=1, errors=1)

message = r"E\s+RuntimeError: Server process \d+ exited with code: 0"
message = r"E\s+RuntimeError: Server process \d+ exited with return code: 0"
results.stdout.re_match_lines(message)
results.stdout.fnmatch_lines("E*RuntimeError: Client has been stopped.")

Expand All @@ -183,7 +183,7 @@ async def test_capabilities(client):

results.assert_outcomes(errors=1)

message = r"E\s+RuntimeError: Server process \d+ exited with code: 1"
message = r"E\s+RuntimeError: Server process \d+ exited with return code: 1"
results.stdout.re_match_lines(message)
results.stdout.fnmatch_lines("ZeroDivisionError: division by zero")

Expand Down Expand Up @@ -215,11 +215,7 @@ async def test_capabilities(client):
setup_test(pytester, "invalid_json.py", test_code)
results = pytester.runpytest("-vv")

results.assert_outcomes(errors=1, failed=1)

if sys.version_info < (3, 9):
message = "E*CancelledError"
else:
message = "E*asyncio.exceptions.CancelledError: JsonRpcInternalError: *"
results.assert_outcomes(failed=1)

message = "E*json.decoder.JSONDecodeError: *"
results.stdout.fnmatch_lines(message)