Skip to content

Commit 9f39e42

Browse files
committed
refactor and reimplement running coroutines in separate threads
1 parent 3a6d2e8 commit 9f39e42

File tree

19 files changed

+189
-89
lines changed

19 files changed

+189
-89
lines changed

robotcode/debugger/launcher/server.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def connected(self) -> bool:
7373
return self._client is not None and self._client.connected
7474

7575
@rpc_method(name="initialize", param_type=InitializeRequestArguments)
76-
async def _initialize(self, arguments: InitializeRequestArguments) -> Capabilities:
76+
async def _initialize(self, arguments: InitializeRequestArguments, *args: Any, **kwargs: Any) -> Capabilities:
7777
self._initialized = True
7878

7979
return Capabilities(
@@ -141,7 +141,8 @@ async def _launch(
141141
groupOutput: Optional[bool] = False,
142142
stopOnEntry: Optional[bool] = False, # noqa: N803
143143
arguments: Optional[LaunchRequestArguments] = None,
144-
**kwargs: Any,
144+
*_args: Any,
145+
**_kwargs: Any,
145146
) -> None:
146147
from ...utils.net import find_free_port
147148

@@ -235,11 +236,13 @@ async def _launch(
235236
raise asyncio.TimeoutError("Can't connect to debug launcher.")
236237

237238
@rpc_method(name="configurationDone", param_type=ConfigurationDoneArguments)
238-
async def _configuration_done(self, arguments: Optional[ConfigurationDoneArguments] = None) -> None:
239+
async def _configuration_done(
240+
self, arguments: Optional[ConfigurationDoneArguments] = None, *args: Any, **kwargs: Any
241+
) -> None:
239242
await self.client.protocol.send_request_async(ConfigurationDoneRequest(arguments=arguments))
240243

241244
@rpc_method(name="disconnect", param_type=DisconnectArguments)
242-
async def _disconnect(self, arguments: Optional[DisconnectArguments] = None) -> None:
245+
async def _disconnect(self, arguments: Optional[DisconnectArguments] = None, *args: Any, **kwargs: Any) -> None:
243246
if self.connected:
244247
if not self.client.protocol.terminated:
245248
await self.client.protocol.send_request_async(DisconnectRequest(arguments=arguments))
@@ -248,7 +251,7 @@ async def _disconnect(self, arguments: Optional[DisconnectArguments] = None) ->
248251

249252
@_logger.call
250253
@rpc_method(name="terminate", param_type=TerminateArguments)
251-
async def _terminate(self, arguments: Optional[TerminateArguments] = None) -> None:
254+
async def _terminate(self, arguments: Optional[TerminateArguments] = None, *args: Any, **kwargs: Any) -> None:
252255
if self.client.connected:
253256
return await self.client.protocol.send_request_async(TerminateRequest(arguments=arguments))
254257
else:

robotcode/debugger/server.py

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ async def terminate(self) -> None:
124124
self._terminated = True
125125

126126
@rpc_method(name="terminate", param_type=TerminateArguments)
127-
async def _terminate(self, arguments: Optional[TerminateArguments] = None) -> None:
127+
async def _terminate(self, arguments: Optional[TerminateArguments] = None, *args: Any, **kwargs: Any) -> None:
128128
import signal
129129

130130
if not self._sigint_signaled:
@@ -138,13 +138,15 @@ async def _terminate(self, arguments: Optional[TerminateArguments] = None) -> No
138138
Debugger.instance().stop()
139139

140140
@rpc_method(name="disconnect", param_type=DisconnectArguments)
141-
async def _disconnect(self, arguments: Optional[DisconnectArguments] = None) -> None:
141+
async def _disconnect(self, arguments: Optional[DisconnectArguments] = None, *args: Any, **kwargs: Any) -> None:
142142
if not (await self.exited) or not (await self.terminated):
143143
if arguments is None or arguments.terminate_debuggee is None or arguments.terminate_debuggee:
144144
os._exit(-1)
145145

146146
@rpc_method(name="setBreakpoints", param_type=SetBreakpointsArguments)
147-
async def _set_breakpoints(self, arguments: SetBreakpointsArguments) -> SetBreakpointsResponseBody:
147+
async def _set_breakpoints(
148+
self, arguments: SetBreakpointsArguments, *args: Any, **kwargs: Any
149+
) -> SetBreakpointsResponseBody:
148150
return SetBreakpointsResponseBody(
149151
breakpoints=Debugger.instance().set_breakpoints(
150152
arguments.source, arguments.breakpoints, arguments.lines, arguments.source_modified
@@ -153,7 +155,9 @@ async def _set_breakpoints(self, arguments: SetBreakpointsArguments) -> SetBreak
153155

154156
@_logger.call
155157
@rpc_method(name="configurationDone", param_type=ConfigurationDoneArguments)
156-
async def _configuration_done(self, arguments: Optional[ConfigurationDoneArguments] = None) -> None:
158+
async def _configuration_done(
159+
self, arguments: Optional[ConfigurationDoneArguments] = None, *args: Any, **kwargs: Any
160+
) -> None:
157161
self._received_configuration_done = True
158162
self._received_configuration_done_event.set()
159163

@@ -164,39 +168,39 @@ async def wait_for_configuration_done(self, timeout: float = 5) -> bool:
164168
return self._received_configuration_done
165169

166170
@rpc_method(name="continue", param_type=ContinueArguments)
167-
async def _continue(self, arguments: ContinueArguments) -> ContinueResponseBody:
171+
async def _continue(self, arguments: ContinueArguments, *args: Any, **kwargs: Any) -> ContinueResponseBody:
168172
Debugger.instance().continue_thread(arguments.thread_id)
169173
return ContinueResponseBody(all_threads_continued=True)
170174

171175
@rpc_method(name="pause", param_type=PauseArguments)
172-
async def _pause(self, arguments: PauseArguments) -> None:
176+
async def _pause(self, arguments: PauseArguments, *args: Any, **kwargs: Any) -> None:
173177
Debugger.instance().pause_thread(arguments.thread_id)
174178

175179
@rpc_method(name="next", param_type=NextArguments)
176-
async def _next(self, arguments: NextArguments) -> None:
180+
async def _next(self, arguments: NextArguments, *args: Any, **kwargs: Any) -> None:
177181
Debugger.instance().next(arguments.thread_id, arguments.granularity)
178182

179183
@rpc_method(name="stepIn", param_type=StepInArguments)
180-
async def _step_in(self, arguments: StepInArguments) -> None:
184+
async def _step_in(self, arguments: StepInArguments, *args: Any, **kwargs: Any) -> None:
181185
Debugger.instance().step_in(arguments.thread_id, arguments.target_id, arguments.granularity)
182186

183187
@rpc_method(name="stepOut", param_type=StepOutArguments)
184-
async def _step_out(self, arguments: StepOutArguments) -> None:
188+
async def _step_out(self, arguments: StepOutArguments, *args: Any, **kwargs: Any) -> None:
185189
Debugger.instance().step_out(arguments.thread_id, arguments.granularity)
186190

187191
@rpc_method(name="threads")
188-
async def _threads(self) -> ThreadsResponseBody:
192+
async def _threads(self, *args: Any, **kwargs: Any) -> ThreadsResponseBody:
189193
return ThreadsResponseBody(threads=Debugger.instance().get_threads())
190194

191195
@rpc_method(name="stackTrace", param_type=StackTraceArguments)
192-
async def _stack_trace(self, arguments: StackTraceArguments) -> StackTraceResponseBody:
196+
async def _stack_trace(self, arguments: StackTraceArguments, *args: Any, **kwargs: Any) -> StackTraceResponseBody:
193197
result = Debugger.instance().get_stack_trace(
194198
arguments.thread_id, arguments.start_frame, arguments.levels, arguments.format
195199
)
196200
return StackTraceResponseBody(stack_frames=result.stack_frames, total_frames=result.total_frames)
197201

198202
@rpc_method(name="scopes", param_type=ScopesArguments)
199-
async def _scopes(self, arguments: ScopesArguments) -> ScopesResponseBody:
203+
async def _scopes(self, arguments: ScopesArguments, *args: Any, **kwargs: Any) -> ScopesResponseBody:
200204
return ScopesResponseBody(scopes=Debugger.instance().get_scopes(arguments.frame_id))
201205

202206
@rpc_method(name="variables", param_type=VariablesArguments)
@@ -208,6 +212,8 @@ async def _variables(
208212
start: Optional[int] = None,
209213
count: Optional[int] = None,
210214
format: Optional[ValueFormat] = None,
215+
*args: Any,
216+
**kwargs: Any,
211217
) -> VariablesResponseBody:
212218
return VariablesResponseBody(
213219
variables=Debugger.instance().get_variables(variables_reference, filter, start, count, format)
@@ -221,6 +227,8 @@ async def _evaluate(
221227
frame_id: Optional[int] = None,
222228
context: Union[EvaluateArgumentContext, str, None] = None,
223229
format: Optional[ValueFormat] = None,
230+
*args: Any,
231+
**kwargs: Any,
224232
) -> EvaluateResponseBody:
225233
result = Debugger.instance().evaluate(expression, frame_id, context, format)
226234
return EvaluateResponseBody(
@@ -241,6 +249,8 @@ async def _set_variable(
241249
name: str,
242250
value: str,
243251
format: Optional[ValueFormat] = None,
252+
*args: Any,
253+
**kwargs: Any,
244254
) -> SetVariableResponseBody:
245255
result = Debugger.instance().set_variable(variables_reference, name, value, format)
246256
return SetVariableResponseBody(
@@ -253,7 +263,7 @@ async def _set_variable(
253263

254264
@rpc_method(name="setExceptionBreakpoints", param_type=SetExceptionBreakpointsArguments)
255265
async def _set_exception_breakpoints(
256-
self, arguments: SetExceptionBreakpointsArguments
266+
self, arguments: SetExceptionBreakpointsArguments, *args: Any, **kwargs: Any
257267
) -> Optional[SetExceptionBreakpointsResponseBody]:
258268
result = Debugger.instance().set_exception_breakpoints(
259269
arguments.filters, arguments.filter_options, arguments.exception_options

robotcode/jsonrpc2/protocol.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
runtime_checkable,
3232
)
3333

34-
from ..utils.async_tools import async_event
34+
from ..utils.async_tools import CancelationToken, async_event
3535
from ..utils.dataclasses import as_json, from_dict
3636
from ..utils.inspect import ensure_coroutine, iter_methods
3737
from ..utils.logging import LoggingDescriptor
@@ -57,8 +57,8 @@
5757
"JsonRPCErrorException",
5858
]
5959

60-
T = TypeVar("T")
61-
TResult = TypeVar("TResult", bound=Any)
60+
_T = TypeVar("_T")
61+
_TResult = TypeVar("_TResult", bound=Any)
6262

6363

6464
class JsonRPCErrors:
@@ -318,6 +318,7 @@ class SendedRequestEntry(NamedTuple):
318318
class ReceivedRequestEntry(NamedTuple):
319319
future: asyncio.Future[Any]
320320
request: Optional[Any]
321+
cancel_token: CancelationToken
321322

322323

323324
class JsonRPCProtocolBase(asyncio.Protocol, ABC):
@@ -517,10 +518,10 @@ def send_request(
517518
self,
518519
method: str,
519520
params: Optional[Any] = None,
520-
return_type_or_converter: Optional[Type[TResult]] = None,
521-
) -> asyncio.Future[TResult]:
521+
return_type_or_converter: Optional[Type[_TResult]] = None,
522+
) -> asyncio.Future[_TResult]:
522523

523-
result: asyncio.Future[TResult] = asyncio.get_event_loop().create_future()
524+
result: asyncio.Future[_TResult] = asyncio.get_event_loop().create_future()
524525

525526
with self._sended_request_lock:
526527
self._sended_request_count += 1
@@ -536,8 +537,8 @@ async def send_request_async(
536537
self,
537538
method: str,
538539
params: Optional[Any] = None,
539-
return_type: Optional[Type[TResult]] = None,
540-
) -> TResult:
540+
return_type: Optional[Type[_TResult]] = None,
541+
) -> _TResult:
541542
return await self.send_request(method, params, return_type)
542543

543544
def send_notification(self, method: str, params: Any) -> None:
@@ -629,7 +630,7 @@ def _convert_params(
629630
kw_args["params"] = converted_params
630631
return args, kw_args
631632

632-
async def handle_request(self, message: JsonRPCRequest) -> None:
633+
async def handle_request(self, message: JsonRPCRequest) -> Optional[asyncio.Task[_T]]:
633634
e = self.registry.get_entry(message.method)
634635

635636
if e is None or not callable(e.method):
@@ -638,14 +639,17 @@ async def handle_request(self, message: JsonRPCRequest) -> None:
638639
f"Unknown method: {message.method}",
639640
id=message.id,
640641
)
641-
return
642+
return None
642643

643644
params = self._convert_params(e.method, e.param_type, message.params)
645+
cancel_token = CancelationToken()
644646

645-
result = asyncio.create_task(ensure_coroutine(e.method)(*params[0], **params[1]), name=message.method)
647+
task = asyncio.create_task(
648+
ensure_coroutine(e.method)(*params[0], cancel_token=cancel_token, **params[1]), name=message.method
649+
)
646650

647651
with self._received_request_lock:
648-
self._received_request[message.id] = ReceivedRequestEntry(result, message)
652+
self._received_request[message.id] = ReceivedRequestEntry(task, message, cancel_token)
649653

650654
def done(t: asyncio.Task[Any]) -> None:
651655
try:
@@ -664,18 +668,22 @@ def done(t: asyncio.Task[Any]) -> None:
664668
with self._received_request_lock:
665669
self._received_request.pop(message.id, None)
666670

667-
result.add_done_callback(done)
671+
task.add_done_callback(done)
672+
673+
return task
668674

669675
async def cancel_request(self, id: Union[int, str, None]) -> None:
670676
with self._received_request_lock:
671677
entry = self._received_request.get(id, None)
672678
if entry is not None and entry.future is not None and not entry.future.cancelled():
673679
self._logger.debug(f"try to cancel request {entry.request}")
680+
entry.cancel_token.cancel()
674681
entry.future.cancel()
675682

676683
async def cancel_all_received_request(self) -> None:
677684
for entry in self._received_request.values():
678685
if entry is not None and entry.future is not None and not entry.future.cancelled():
686+
entry.cancel_token.cancel()
679687
entry.future.cancel()
680688

681689
async def handle_notification(self, message: JsonRPCNotification) -> None:

robotcode/language_server/common/parts/completion.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ async def _text_document_completion(
116116
async def _completion_item_resolve(
117117
self,
118118
params: CompletionItem,
119+
*args: Any,
120+
**kwargs: Any,
119121
) -> CompletionItem:
120122

121123
results: List[CompletionItem] = []

robotcode/language_server/common/parts/hover.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import TYPE_CHECKING, Any, List, Optional
55

66
from ....jsonrpc2.protocol import rpc_method
7-
from ....utils.async_tools import async_tasking_event
7+
from ....utils.async_tools import CancelationToken, async_tasking_event
88
from ....utils.logging import LoggingDescriptor
99
from ..has_extend_capabilities import HasExtendCapabilities
1010
from ..language import language_id_filter
@@ -31,7 +31,9 @@ def __init__(self, parent: LanguageServerProtocol) -> None:
3131
super().__init__(parent)
3232

3333
@async_tasking_event
34-
async def collect(sender, document: TextDocument, position: Position) -> Optional[Hover]: # NOSONAR
34+
async def collect(
35+
sender, document: TextDocument, position: Position, cancel_token: Optional[CancelationToken] = None
36+
) -> Optional[Hover]: # NOSONAR
3537
...
3638

3739
def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
@@ -40,7 +42,12 @@ def extend_capabilities(self, capabilities: ServerCapabilities) -> None:
4042

4143
@rpc_method(name="textDocument/hover", param_type=HoverParams)
4244
async def _text_document_hover(
43-
self, text_document: TextDocumentIdentifier, position: Position, *args: Any, **kwargs: Any
45+
self,
46+
text_document: TextDocumentIdentifier,
47+
position: Position,
48+
cancel_token: Optional[CancelationToken] = None,
49+
*args: Any,
50+
**kwargs: Any,
4451
) -> Optional[Hover]:
4552

4653
results: List[Hover] = []
@@ -49,6 +56,7 @@ async def _text_document_hover(
4956
self,
5057
document,
5158
position,
59+
cancel_token=cancel_token,
5260
callback_filter=language_id_filter(document),
5361
):
5462
if isinstance(result, BaseException):

robotcode/language_server/common/parts/workspace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class ConfigBase(Model):
125125
pass
126126

127127

128-
_TConfig = TypeVar("_TConfig", bound=(ConfigBase))
128+
_TConfig = TypeVar("_TConfig", bound=ConfigBase)
129129
_F = TypeVar("_F", bound=Callable[..., Any])
130130

131131

robotcode/language_server/common/protocol.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ async def _initialize(
152152
trace: Optional[TraceValue] = None,
153153
client_info: Optional[ClientInfo] = None,
154154
workspace_folders: Optional[List[WorkspaceFolder]] = None,
155+
*args: Any,
155156
**kwargs: Any,
156157
) -> InitializeResult:
157158

@@ -188,7 +189,7 @@ async def on_initialize(sender, initialization_options: Optional[Any] = None) ->
188189
...
189190

190191
@rpc_method(name="initialized", param_type=InitializedParams)
191-
async def _initialized(self, params: InitializedParams) -> None:
192+
async def _initialized(self, params: InitializedParams, *args: Any, **kwargs: Any) -> None:
192193
await self.on_initialized(self)
193194

194195
@async_event
@@ -197,7 +198,7 @@ async def on_initialized(sender) -> None: # pragma: no cover, NOSONAR
197198

198199
@rpc_method(name="shutdown")
199200
@_logger.call
200-
async def shutdown(self) -> None:
201+
async def shutdown(self, *args: Any, **kwargs: Any) -> None:
201202
self.shutdown_received = True
202203

203204
try:
@@ -211,12 +212,12 @@ async def shutdown(self) -> None:
211212

212213
@rpc_method(name="exit")
213214
@_logger.call
214-
async def _exit(self) -> None:
215+
async def _exit(self, *args: Any, **kwargs: Any) -> None:
215216
raise SystemExit(0 if self.shutdown_received else 1)
216217

217218
@rpc_method(name="$/setTrace", param_type=SetTraceParams)
218219
@_logger.call
219-
async def _set_trace(self, value: TraceValue, **kwargs: Any) -> None:
220+
async def _set_trace(self, value: TraceValue, *args: Any, **kwargs: Any) -> None:
220221
self.trace = value
221222

222223
@rpc_method(name="$/cancelRequest", param_type=CancelParams)

robotcode/language_server/robotframework/diagnostics/analyzer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ async def get(
4141

4242
async def visit(self, node: ast.AST) -> None:
4343
if self.cancelation_token:
44-
self.cancelation_token.throw_if_canceled()
44+
self.cancelation_token.raise_if_canceled()
4545

4646
await super().visit(node)
4747

0 commit comments

Comments
 (0)