Skip to content

Commit 89e3eb6

Browse files
committed
introduce cancelation_token to diagnostics, some renaming
1 parent c4cac21 commit 89e3eb6

File tree

10 files changed

+93
-43
lines changed

10 files changed

+93
-43
lines changed

robotcode/language_server/common/parts/diagnostics.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from dataclasses import dataclass
66
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, cast
77

8-
from ....utils.async_tools import async_tasking_event_iterator
8+
from ....utils.async_tools import CancelationToken, async_tasking_event_iterator
99
from ....utils.logging import LoggingDescriptor
1010
from ....utils.uri import Uri
1111
from ..language import language_id, language_id_filter
@@ -25,14 +25,21 @@
2525
class PublishDiagnosticsEntry:
2626
_logger = LoggingDescriptor()
2727

28-
def __init__(self, document_uri: DocumentUri, task_factory: Callable[..., asyncio.Task[Any]]) -> None:
28+
def __init__(
29+
self,
30+
document_uri: DocumentUri,
31+
cancelation_token: CancelationToken,
32+
task_factory: Callable[..., asyncio.Task[Any]],
33+
) -> None:
2934

3035
self._document_uri = document_uri
3136

3237
self._task_factory = task_factory
3338

3439
self._task: Optional[asyncio.Task[Any]] = None
3540

41+
self.cancel_token = cancelation_token
42+
3643
@PublishDiagnosticsEntry._logger.call
3744
def create_task() -> None:
3845
self._task = self._task_factory()
@@ -74,6 +81,7 @@ async def cancel() -> None:
7481
t = self.task
7582
self._task = None
7683
if not t.done():
84+
self.cancel_token.cancel()
7785
t.cancel()
7886
try:
7987
await t
@@ -109,7 +117,9 @@ def __init__(self, protocol: LanguageServerProtocol) -> None:
109117
self.parent.documents.did_save.add(self.on_did_save)
110118

111119
@async_tasking_event_iterator
112-
async def collect(sender, document: TextDocument) -> DiagnosticsResult: # NOSONAR
120+
async def collect(
121+
sender, document: TextDocument, cancelation_token: CancelationToken
122+
) -> DiagnosticsResult: # NOSONAR
113123
...
114124

115125
@_logger.call
@@ -166,16 +176,17 @@ async def on_did_change(self, sender: Any, document: TextDocument) -> None:
166176
async def start_publish_diagnostics_task(self, document: TextDocument) -> None:
167177
async with self._task_lock:
168178
self._cancel_entry(self._running_diagnostics.get(document.uri, None))
169-
179+
cancelation_token = CancelationToken()
170180
self._running_diagnostics[document.uri] = PublishDiagnosticsEntry(
171181
document.document_uri,
182+
cancelation_token,
172183
lambda: asyncio.create_task(
173-
self.publish_diagnostics(document.document_uri),
184+
self.publish_diagnostics(document.document_uri, cancelation_token),
174185
),
175186
)
176187

177188
@_logger.call
178-
async def publish_diagnostics(self, document_uri: DocumentUri) -> None:
189+
async def publish_diagnostics(self, document_uri: DocumentUri, cancelation_token: CancelationToken) -> None:
179190
document = self.parent.documents.get(document_uri, None)
180191
if document is None:
181192
return
@@ -187,6 +198,7 @@ async def publish_diagnostics(self, document_uri: DocumentUri) -> None:
187198
async for result_any in self.collect(
188199
self,
189200
document,
201+
cancelation_token,
190202
callback_filter=language_id_filter(document),
191203
return_exceptions=True,
192204
):

robotcode/language_server/robotframework/diagnostics/analyzer.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import asyncio
55
from typing import List, Optional, cast
66

7+
from ....utils.async_tools import CancelationToken
78
from ....utils.uri import Uri
89
from ...common.lsp_types import (
910
Diagnostic,
@@ -26,16 +27,24 @@
2627

2728

2829
class Analyzer(AsyncVisitor):
29-
async def get(self, model: ast.AST, namespace: Namespace) -> List[Diagnostic]:
30+
async def get(
31+
self, model: ast.AST, namespace: Namespace, cancelation_token: Optional[CancelationToken] = None
32+
) -> List[Diagnostic]:
3033
self._results: List[Diagnostic] = []
3134
self._namespace = namespace
32-
35+
self.cancelation_token = cancelation_token
3336
self.current_testcase_or_keyword_name: Optional[str] = None
3437
self.finder = KeywordFinder(self._namespace)
3538

3639
await self.visit(model)
3740
return self._results
3841

42+
async def visit(self, node: ast.AST) -> None:
43+
if self.cancelation_token:
44+
self.cancelation_token.throw_if_canceled()
45+
46+
await super().visit(node)
47+
3948
async def _analyze_keyword_call(
4049
self,
4150
keyword: Optional[str],

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424

2525
from ....utils.async_itertools import async_chain
26-
from ....utils.async_tools import awaitable_to_thread
26+
from ....utils.async_tools import CancelationToken, awaitable_run_in_thread
2727
from ....utils.logging import LoggingDescriptor
2828
from ....utils.uri import Uri
2929
from ...common.lsp_types import (
@@ -577,10 +577,10 @@ async def invalidate(self) -> None:
577577
self.invalidated_callback(self)
578578

579579
@_logger.call
580-
async def get_diagnostisc(self) -> List[Diagnostic]:
580+
async def get_diagnostisc(self, cancelation_token: Optional[CancelationToken] = None) -> List[Diagnostic]:
581581
await self.ensure_initialized()
582582

583-
await self._analyze()
583+
await self._analyze(cancelation_token)
584584

585585
return self._diagnostics
586586

@@ -1088,14 +1088,16 @@ async def get_keywords(self) -> List[KeywordDoc]:
10881088
return self._keywords
10891089

10901090
@_logger.call
1091-
async def _analyze(self) -> None:
1091+
async def _analyze(self, cancelation_token: Optional[CancelationToken] = None) -> None:
10921092
from .analyzer import Analyzer
10931093

10941094
if not self._analyzed:
10951095
async with self._analyze_lock:
10961096
if not self._analyzed:
10971097
try:
1098-
self._diagnostics += await awaitable_to_thread(Analyzer().get(self.model, self))
1098+
self._diagnostics += await awaitable_run_in_thread(
1099+
Analyzer().get(self.model, self, cancelation_token)
1100+
)
10991101

11001102
lib_doc = await self.get_library_doc()
11011103

robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
from __future__ import annotations
22

33
import ast
4+
import asyncio
45
from typing import TYPE_CHECKING, Any, List, Optional
56

6-
from ....utils.async_tools import awaitable_to_thread
7+
from ....utils.async_tools import CancelationToken, awaitable_run_in_thread
78
from ....utils.logging import LoggingDescriptor
89
from ...common.language import language_id
910
from ...common.lsp_types import Diagnostic, DiagnosticSeverity, Position, Range
@@ -60,14 +61,18 @@ def _create_error_from_token(self, token: Token, source: Optional[str] = None) -
6061

6162
@language_id("robotframework")
6263
@_logger.call
63-
async def collect_token_errors(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
64+
async def collect_token_errors(
65+
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
66+
) -> DiagnosticsResult:
6467
async def collect_async(tokens: List[Token]) -> List[Diagnostic]:
6568
from robot.errors import VariableError
6669
from robot.parsing.lexer.tokens import Token
6770

6871
result: List[Diagnostic] = []
6972
try:
7073
for token in tokens:
74+
cancelation_token.throw_if_canceled()
75+
7176
if token.type in [Token.ERROR, Token.FATAL_ERROR]:
7277
result.append(self._create_error_from_token(token))
7378

@@ -89,8 +94,7 @@ async def collect_async(tokens: List[Token]) -> List[Diagnostic]:
8994
code=type(e).__qualname__,
9095
)
9196
)
92-
93-
except (SystemExit, KeyboardInterrupt):
97+
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
9498
raise
9599
except BaseException as e:
96100
return [
@@ -116,18 +120,22 @@ async def collect_async(tokens: List[Token]) -> List[Diagnostic]:
116120

117121
return DiagnosticsResult(
118122
self.collect_token_errors,
119-
await awaitable_to_thread(collect_async(await self.parent.documents_cache.get_tokens(document))),
123+
await awaitable_run_in_thread(collect_async(await self.parent.documents_cache.get_tokens(document))),
120124
)
121125

122126
@language_id("robotframework")
123127
@_logger.call
124-
async def collect_walk_model_errors(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
128+
async def collect_walk_model_errors(
129+
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
130+
) -> DiagnosticsResult:
125131
async def collect_async(model: ast.AST) -> List[Diagnostic]:
126132
from ..utils.ast import HasError, HasErrors
127133
from ..utils.async_ast import iter_nodes
128134

129135
result: List[Diagnostic] = []
130136
async for node in iter_nodes(model):
137+
cancelation_token.throw_if_canceled()
138+
131139
error = node.error if isinstance(node, HasError) else None
132140
if error is not None:
133141
result.append(self._create_error_from_node(node, error))
@@ -139,14 +147,16 @@ async def collect_async(model: ast.AST) -> List[Diagnostic]:
139147

140148
return DiagnosticsResult(
141149
self.collect_walk_model_errors,
142-
await awaitable_to_thread(collect_async(await self.parent.documents_cache.get_model(document))),
150+
await awaitable_run_in_thread(collect_async(await self.parent.documents_cache.get_model(document))),
143151
)
144152

145153
@language_id("robotframework")
146154
@_logger.call
147-
async def collect_namespace_diagnostics(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
155+
async def collect_namespace_diagnostics(
156+
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
157+
) -> DiagnosticsResult:
148158
namespace = await self.parent.documents_cache.get_namespace(document)
149159
if namespace is None:
150160
return DiagnosticsResult(self.collect_namespace_diagnostics, None)
151161

152-
return DiagnosticsResult(self.collect_namespace_diagnostics, await namespace.get_diagnostisc())
162+
return DiagnosticsResult(self.collect_namespace_diagnostics, await namespace.get_diagnostisc(cancelation_token))

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing import TYPE_CHECKING, Iterator, List, Optional
88

99
from ....jsonrpc2.protocol import rpc_method
10-
from ....utils.async_tools import to_thread
10+
from ....utils.async_tools import run_in_thread
1111
from ....utils.logging import LoggingDescriptor
1212
from ....utils.uri import Uri
1313
from ...common.lsp_types import (
@@ -163,7 +163,7 @@ def nonexisting_paths(paths: List[str]) -> Iterator[str]:
163163

164164
@rpc_method(name="robot/discovering/getTestsFromWorkspace", param_type=GetAllTestsParams)
165165
async def get_tests_from_workspace(self, paths: Optional[List[str]]) -> List[TestItem]:
166-
return await to_thread(self.get_tests_from_workspace_threading, paths)
166+
return await run_in_thread(self.get_tests_from_workspace_threading, paths)
167167

168168
def get_tests_from_document_threading(
169169
self, text_document: TextDocumentIdentifier, id: Optional[str], model: ast.AST
@@ -194,7 +194,7 @@ def get_tests_from_document_threading(
194194

195195
@rpc_method(name="robot/discovering/getTestsFromDocument", param_type=GetTestsParams)
196196
async def get_tests_from_document(self, text_document: TextDocumentIdentifier, id: Optional[str]) -> List[TestItem]:
197-
return await to_thread(
197+
return await run_in_thread(
198198
self.get_tests_from_document_threading,
199199
text_document,
200200
id,

robotcode/language_server/robotframework/parts/documents_cache.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
cast,
1717
)
1818

19-
from ....utils.async_tools import CancelationToken, async_tasking_event, to_thread
19+
from ....utils.async_tools import CancelationToken, async_tasking_event, run_in_thread
2020
from ....utils.uri import Uri
2121
from ...common.language import language_id_filter
2222
from ...common.parts.workspace import WorkspaceFolder
@@ -111,7 +111,7 @@ async def __get_tokens_internal(
111111
try:
112112
if cancelation_token is None:
113113
cancelation_token = CancelationToken()
114-
return await to_thread(get, document.text, cancelation_token)
114+
return await run_in_thread(get, document.text, cancelation_token)
115115
except asyncio.CancelledError:
116116
if cancelation_token is not None:
117117
cancelation_token.cancel()
@@ -181,7 +181,7 @@ def get_tokens(_source: str, _data_only: bool = False) -> Generator[Token, None,
181181
yield t
182182

183183
try:
184-
model = await to_thread(_get_model, get_tokens, document.uri.to_path())
184+
model = await run_in_thread(_get_model, get_tokens, document.uri.to_path())
185185
except asyncio.CancelledError:
186186
if cancelation_token is not None:
187187
cancelation_token.cancel()

robotcode/language_server/robotframework/parts/references.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
cast,
1717
)
1818

19-
from ....utils.async_tools import CancelationToken, awaitable_to_thread
19+
from ....utils.async_tools import CancelationToken, awaitable_run_in_thread
2020
from ....utils.glob_path import iter_files
2121
from ....utils.logging import LoggingDescriptor
2222
from ....utils.uri import Uri
@@ -305,7 +305,9 @@ async def _find_keyword_references_in_file(
305305
):
306306
return []
307307

308-
return await awaitable_to_thread(self._find_keyword_references_in_namespace(namespace, kw_doc, cancel_token))
308+
return await awaitable_run_in_thread(
309+
self._find_keyword_references_in_namespace(namespace, kw_doc, cancel_token)
310+
)
309311

310312
async def _find_keyword_references_in_namespace(
311313
self, namespace: Namespace, kw_doc: KeywordDoc, cancel_token: CancelationToken

robotcode/language_server/robotframework/parts/robocop_diagnostics.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import io
66
from typing import TYPE_CHECKING, Any, List, Optional
77

8-
from ....utils.async_tools import to_thread
8+
from ....utils.async_tools import CancelationToken, run_in_thread
99
from ....utils.logging import LoggingDescriptor
1010
from ...common.language import language_id
1111
from ...common.lsp_types import Diagnostic, DiagnosticSeverity, Position, Range
@@ -48,7 +48,9 @@ async def get_config(self, document: TextDocument) -> Optional[RoboCopConfig]:
4848

4949
@language_id("robotframework")
5050
@_logger.call
51-
async def collect_diagnostics(self, sender: Any, document: TextDocument) -> DiagnosticsResult:
51+
async def collect_diagnostics(
52+
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
53+
) -> DiagnosticsResult:
5254

5355
try:
5456
workspace_folder = self.parent.workspace.get_workspace_folder(document.uri)
@@ -58,7 +60,9 @@ async def collect_diagnostics(self, sender: Any, document: TextDocument) -> Diag
5860
if extension_config is not None and extension_config.enabled:
5961

6062
model = await self.parent.documents_cache.get_model(document)
61-
result = await self.collect_threading(document, workspace_folder, extension_config, model)
63+
result = await self.collect_threading(
64+
document, workspace_folder, extension_config, model, cancelation_token
65+
)
6266
return DiagnosticsResult(self.collect_diagnostics, result)
6367
except (SystemExit, KeyboardInterrupt, asyncio.CancelledError):
6468
raise
@@ -68,12 +72,22 @@ async def collect_diagnostics(self, sender: Any, document: TextDocument) -> Diag
6872
return DiagnosticsResult(self.collect_diagnostics, [])
6973

7074
async def collect_threading(
71-
self, document: TextDocument, workspace_folder: WorkspaceFolder, extension_config: RoboCopConfig, model: ast.AST
75+
self,
76+
document: TextDocument,
77+
workspace_folder: WorkspaceFolder,
78+
extension_config: RoboCopConfig,
79+
model: ast.AST,
80+
cancelation_token: CancelationToken,
7281
) -> List[Diagnostic]:
73-
return await to_thread(self.collect, document, workspace_folder, extension_config, model)
82+
return await run_in_thread(self.collect, document, workspace_folder, extension_config, model, cancelation_token)
7483

7584
def collect(
76-
self, document: TextDocument, workspace_folder: WorkspaceFolder, extension_config: RoboCopConfig, model: ast.AST
85+
self,
86+
document: TextDocument,
87+
workspace_folder: WorkspaceFolder,
88+
extension_config: RoboCopConfig,
89+
model: ast.AST,
90+
cancelation_token: CancelationToken,
7791
) -> List[Diagnostic]:
7892
from robocop.config import Config
7993
from robocop.rules import RuleSeverity
@@ -98,6 +112,7 @@ def collect(
98112
analyser = Robocop(from_cli=False, config=config)
99113
analyser.reload_config()
100114

115+
# TODO find a way to cancel the run_check
101116
issues = analyser.run_check(model, str(document.uri.to_path()), document.text)
102117

103118
for issue in issues:
@@ -117,7 +132,7 @@ def collect(
117132
source=self.source_name,
118133
code=f"{issue.severity.value}{issue.rule_id}",
119134
)
120-
135+
cancelation_token.throw_if_canceled()
121136
result.append(d)
122137

123138
return result

0 commit comments

Comments
 (0)