Skip to content

Commit

Permalink
pytest-lsp: Passthrough requested fixtures to user fixture func
Browse files Browse the repository at this point in the history
  • Loading branch information
alcarney committed Aug 10, 2023
1 parent eee8b4a commit 4b281c0
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 4 deletions.
11 changes: 11 additions & 0 deletions docs/pytest-lsp/guide/fixtures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@ This can be used to run the same set of tests while pretending to be a different
:language: python
:start-at: @pytest_lsp.fixture
:end-at: await lsp_client.shutdown_session()


Requesting Other Fixtures
-------------------------

As you would expect, it's possible to request other fixtures to help set up your client.

.. literalinclude:: ../../../lib/pytest-lsp/tests/examples/fixture-passthrough/t_server.py
:language: python
:start-at: @pytest.fixture
:end-at: await lsp_client.shutdown_session()
1 change: 1 addition & 0 deletions lib/pytest-lsp/changes/71.enhancement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixtures created with the `@pytest_lsp.fixture` decorator can now request additional pytest fixtures
37 changes: 33 additions & 4 deletions lib/pytest-lsp/pytest_lsp/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,46 @@ async def anext(it):
return await it.__anext__()


def get_fixture_arguments(fn: Callable, client: LanguageClient, request) -> dict:
"""Return the arguments to pass to the user's fixture function"""
def get_fixture_arguments(
fn: Callable,
client: LanguageClient,
request: pytest.FixtureRequest,
) -> dict:
"""Return the arguments to pass to the user's fixture function.
Parameters
----------
fn
The user's fixture function
client
The language client instance to inject
request
pytest's request fixture
Returns
-------
dict
The set of arguments to pass to the user's fixture function
"""
kwargs = {}
required_parameters = set(inspect.signature(fn).parameters.keys())

parameters = inspect.signature(fn).parameters
if "request" in parameters:
# Inject the 'request' fixture if requested
if "request" in required_parameters:
kwargs["request"] = request
required_parameters.remove("request")

# Inject the language client
for name, cls in typing.get_type_hints(fn).items():
if issubclass(cls, LanguageClient):
kwargs[name] = client
required_parameters.remove(name)

# Assume all remaining parameters are pytest fixtures
for name in required_parameters:
kwargs[name] = request.getfixturevalue(name)

return kwargs

Expand Down
18 changes: 18 additions & 0 deletions lib/pytest-lsp/tests/examples/fixture-passthrough/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from lsprotocol.types import TEXT_DOCUMENT_COMPLETION
from lsprotocol.types import CompletionItem
from lsprotocol.types import CompletionParams
from pygls.server import LanguageServer

server = LanguageServer("hello-world", "v1")


@server.feature(TEXT_DOCUMENT_COMPLETION)
def completion(ls: LanguageServer, params: CompletionParams):
return [
CompletionItem(label="hello"),
CompletionItem(label="world"),
]


if __name__ == "__main__":
server.start_io()
52 changes: 52 additions & 0 deletions lib/pytest-lsp/tests/examples/fixture-passthrough/t_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import sys

import pytest
from lsprotocol.types import CompletionList
from lsprotocol.types import CompletionParams
from lsprotocol.types import InitializeParams
from lsprotocol.types import Position
from lsprotocol.types import TextDocumentIdentifier

import pytest_lsp
from pytest_lsp import ClientServerConfig
from pytest_lsp import LanguageClient
from pytest_lsp import client_capabilities


@pytest.fixture(scope="module")
def client_name():
return "neovim"


@pytest_lsp.fixture(
config=ClientServerConfig(server_command=[sys.executable, "server.py"]),
)
async def client(client_name: str, lsp_client: LanguageClient):
# Setup
params = InitializeParams(capabilities=client_capabilities(client_name))
await lsp_client.initialize_session(params)

yield

# Teardown
await lsp_client.shutdown_session()


async def test_completions(client: LanguageClient):
"""Ensure that the server implements completions correctly."""

results = await client.text_document_completion_async(
params=CompletionParams(
position=Position(line=1, character=0),
text_document=TextDocumentIdentifier(uri="file:///path/to/file.txt"),
)
)
assert results is not None

if isinstance(results, CompletionList):
items = results.items
else:
items = results

labels = [item.label for item in items]
assert labels == ["hello", "world"]
1 change: 1 addition & 0 deletions lib/pytest-lsp/tests/test_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def setup_test(pytester: pytest.Pytester, example_name: str):
[
("diagnostics", dict(passed=1)),
("getting-started", dict(passed=1)),
("fixture-passthrough", dict(passed=1)),
("parameterised-clients", dict(passed=2)),
("window-log-message", dict(passed=1)),
("window-show-document", dict(passed=1)),
Expand Down

0 comments on commit 4b281c0

Please sign in to comment.