Skip to content

Commit 4db7137

Browse files
DevonFulcherAI Assistant
andcommitted
test(lsp): silence asyncio DeprecationWarning in sync tests
Bind a fresh event loop in the four `TestMessageHandling` tests that build futures synchronously, and use `loop.create_future()` instead of bare `asyncio.Future()`. Without this, pytest emits a `DeprecationWarning: There is no current event loop` and the tests will eventually fail outright on Python versions that drop implicit loop creation. Co-Authored-By: AI Assistant <noreply@ai>
1 parent 73757b0 commit 4db7137

2 files changed

Lines changed: 81 additions & 61 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: Under the Hood
2+
body: Silence asyncio DeprecationWarning in LSP connection unit tests by binding a fresh event loop and using loop.create_future() instead of bare asyncio.Future().
3+
time: 2026-05-13T08:55:13.549958-05:00

tests/unit/lsp/test_lsp_connection.py

Lines changed: 78 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Unit tests for the LSP connection module."""
22

33
import asyncio
4+
import contextlib
45
import socket
56
import subprocess
7+
from collections.abc import Iterator
68
from unittest.mock import AsyncMock, MagicMock, patch
79

810
import pytest
@@ -16,6 +18,18 @@
1618
)
1719

1820

21+
@contextlib.contextmanager
22+
def _sync_test_event_loop() -> Iterator[asyncio.AbstractEventLoop]:
23+
"""Bind a fresh loop so ``asyncio.Future()`` / ``create_future`` is safe in sync tests."""
24+
loop = asyncio.new_event_loop()
25+
asyncio.set_event_loop(loop)
26+
try:
27+
yield loop
28+
finally:
29+
loop.close()
30+
asyncio.set_event_loop(None)
31+
32+
1933
class TestJsonRpcMessage:
2034
"""Test JsonRpcMessage dataclass."""
2135

@@ -555,27 +569,28 @@ def test_handle_response_message(self, tmp_path):
555569

556570
conn = SocketLSPConnection([str(binary_path)], "/test")
557571

558-
# Create a pending request
559-
future = asyncio.Future()
560-
conn.state.pending_requests[42] = future
572+
with _sync_test_event_loop() as loop:
573+
# Create a pending request
574+
future = loop.create_future()
575+
conn.state.pending_requests[42] = future
561576

562-
# Handle response message
563-
message = JsonRpcMessage(id=42, result={"success": True})
577+
# Handle response message
578+
message = JsonRpcMessage(id=42, result={"success": True})
564579

565-
with patch.object(future, "get_loop") as mock_get_loop:
566-
mock_loop = MagicMock()
567-
mock_get_loop.return_value = mock_loop
580+
with patch.object(future, "get_loop") as mock_get_loop:
581+
mock_loop = MagicMock()
582+
mock_get_loop.return_value = mock_loop
568583

569-
conn._handle_incoming_message(message)
584+
conn._handle_incoming_message(message)
570585

571-
# Verify future was resolved
572-
mock_loop.call_soon_threadsafe.assert_called_once()
573-
args = mock_loop.call_soon_threadsafe.call_args[0]
574-
assert args[0] == future.set_result
575-
assert args[1] == {"success": True}
586+
# Verify future was resolved
587+
mock_loop.call_soon_threadsafe.assert_called_once()
588+
args = mock_loop.call_soon_threadsafe.call_args[0]
589+
assert args[0] == future.set_result
590+
assert args[1] == {"success": True}
576591

577-
# Verify request was removed from pending
578-
assert 42 not in conn.state.pending_requests
592+
# Verify request was removed from pending
593+
assert 42 not in conn.state.pending_requests
579594

580595
def test_handle_error_response(self, tmp_path):
581596
"""Test handling error response."""
@@ -584,25 +599,26 @@ def test_handle_error_response(self, tmp_path):
584599

585600
conn = SocketLSPConnection([str(binary_path)], "/test")
586601

587-
# Create a pending request
588-
future = asyncio.Future()
589-
conn.state.pending_requests[42] = future
602+
with _sync_test_event_loop() as loop:
603+
# Create a pending request
604+
future = loop.create_future()
605+
conn.state.pending_requests[42] = future
590606

591-
# Handle error response
592-
message = JsonRpcMessage(
593-
id=42, error={"code": -32601, "message": "Method not found"}
594-
)
607+
# Handle error response
608+
message = JsonRpcMessage(
609+
id=42, error={"code": -32601, "message": "Method not found"}
610+
)
595611

596-
with patch.object(future, "get_loop") as mock_get_loop:
597-
mock_loop = MagicMock()
598-
mock_get_loop.return_value = mock_loop
612+
with patch.object(future, "get_loop") as mock_get_loop:
613+
mock_loop = MagicMock()
614+
mock_get_loop.return_value = mock_loop
599615

600-
conn._handle_incoming_message(message)
616+
conn._handle_incoming_message(message)
601617

602-
# Verify future was rejected
603-
mock_loop.call_soon_threadsafe.assert_called_once()
604-
args = mock_loop.call_soon_threadsafe.call_args[0]
605-
assert args[0] == future.set_exception
618+
# Verify future was rejected
619+
mock_loop.call_soon_threadsafe.assert_called_once()
620+
args = mock_loop.call_soon_threadsafe.call_args[0]
621+
assert args[0] == future.set_exception
606622

607623
def test_handle_unknown_response(self, tmp_path):
608624
"""Test handling response for unknown request ID."""
@@ -631,40 +647,41 @@ def test_handle_notification(self, tmp_path):
631647

632648
conn = SocketLSPConnection([str(binary_path)], "/test")
633649

634-
# Create futures waiting for compile complete event
635-
future1 = asyncio.Future()
636-
future2 = asyncio.Future()
637-
conn.state.pending_notifications[LspEventName.compileComplete] = [
638-
future1,
639-
future2,
640-
]
641-
642-
# Handle compile complete notification
643-
message = JsonRpcMessage(
644-
method="dbt/lspCompileComplete", params={"success": True}
645-
)
650+
with _sync_test_event_loop() as loop:
651+
# Create futures waiting for compile complete event
652+
future1 = loop.create_future()
653+
future2 = loop.create_future()
654+
conn.state.pending_notifications[LspEventName.compileComplete] = [
655+
future1,
656+
future2,
657+
]
658+
659+
# Handle compile complete notification
660+
message = JsonRpcMessage(
661+
method="dbt/lspCompileComplete", params={"success": True}
662+
)
646663

647-
with (
648-
patch.object(future1, "get_loop") as mock_get_loop1,
649-
patch.object(future2, "get_loop") as mock_get_loop2,
650-
):
651-
mock_loop1 = MagicMock()
652-
mock_loop2 = MagicMock()
653-
mock_get_loop1.return_value = mock_loop1
654-
mock_get_loop2.return_value = mock_loop2
664+
with (
665+
patch.object(future1, "get_loop") as mock_get_loop1,
666+
patch.object(future2, "get_loop") as mock_get_loop2,
667+
):
668+
mock_loop1 = MagicMock()
669+
mock_loop2 = MagicMock()
670+
mock_get_loop1.return_value = mock_loop1
671+
mock_get_loop2.return_value = mock_loop2
655672

656-
conn._handle_incoming_message(message)
673+
conn._handle_incoming_message(message)
657674

658-
# Verify futures were resolved
659-
mock_loop1.call_soon_threadsafe.assert_called_once_with(
660-
future1.set_result, {"success": True}
661-
)
662-
mock_loop2.call_soon_threadsafe.assert_called_once_with(
663-
future2.set_result, {"success": True}
664-
)
675+
# Verify futures were resolved
676+
mock_loop1.call_soon_threadsafe.assert_called_once_with(
677+
future1.set_result, {"success": True}
678+
)
679+
mock_loop2.call_soon_threadsafe.assert_called_once_with(
680+
future2.set_result, {"success": True}
681+
)
665682

666-
# Verify compile state was set
667-
assert conn.state.compiled is True
683+
# Verify compile state was set
684+
assert conn.state.compiled is True
668685

669686
def test_handle_unknown_notification(self, tmp_path):
670687
"""Test handling unknown notification."""

0 commit comments

Comments
 (0)