robotcode-robot 0.91.0__py3-none-any.whl → 0.93.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- robotcode/robot/__version__.py +1 -1
- robotcode/robot/config/loader.py +75 -21
- robotcode/robot/config/model.py +105 -100
- robotcode/robot/config/utils.py +4 -2
- robotcode/robot/diagnostics/diagnostics_modifier.py +80 -17
- robotcode/robot/diagnostics/document_cache_helper.py +25 -7
- robotcode/robot/diagnostics/entities.py +2 -2
- robotcode/robot/diagnostics/imports_manager.py +79 -64
- robotcode/robot/diagnostics/library_doc.py +25 -8
- robotcode/robot/diagnostics/namespace.py +105 -102
- robotcode/robot/diagnostics/workspace_config.py +17 -0
- robotcode/robot/utils/ast.py +34 -7
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/METADATA +2 -2
- robotcode_robot-0.93.0.dist-info/RECORD +30 -0
- robotcode_robot-0.91.0.dist-info/RECORD +0 -30
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -2,7 +2,8 @@ import functools
|
|
2
2
|
import re as re
|
3
3
|
from ast import AST
|
4
4
|
from collections import defaultdict
|
5
|
-
from dataclasses import dataclass
|
5
|
+
from dataclasses import dataclass, field
|
6
|
+
from enum import Enum
|
6
7
|
from typing import Dict, List, Optional, Set, Union
|
7
8
|
|
8
9
|
from robot.parsing.lexer.tokens import Token
|
@@ -12,15 +13,32 @@ from robotcode.core.lsp.types import Diagnostic, DiagnosticSeverity
|
|
12
13
|
|
13
14
|
from ..utils.visitor import Visitor
|
14
15
|
|
15
|
-
ACTIONS = ["ignore", "error", "warn", "information", "hint", "reset"]
|
16
|
+
ACTIONS = ["ignore", "error", "warn", "warning", "info", "information", "hint", "reset"]
|
16
17
|
|
17
18
|
ROBOTCODE_ACTION_AND_CODES_PATTERN = re.compile(rf"(?P<action>{'|'.join(ACTIONS)})(\[(?P<codes>[^\]]*?)\])?")
|
18
19
|
|
19
20
|
|
21
|
+
class ModifierAction(Enum):
|
22
|
+
IGNORE = "ignore"
|
23
|
+
ERROR = "error"
|
24
|
+
WARNING = "warning"
|
25
|
+
INFORMATION = "information"
|
26
|
+
HINT = "hint"
|
27
|
+
RESET = "reset"
|
28
|
+
|
29
|
+
@classmethod
|
30
|
+
def from_str(cls, value: str) -> "ModifierAction":
|
31
|
+
if value == "warn":
|
32
|
+
value = "warning"
|
33
|
+
elif value == "info":
|
34
|
+
value = "information"
|
35
|
+
return cls(value)
|
36
|
+
|
37
|
+
|
20
38
|
@dataclass
|
21
39
|
class RulesAndCodes:
|
22
40
|
codes: Dict[Union[str, int], Set[int]]
|
23
|
-
actions: Dict[int, Dict[Union[str, int],
|
41
|
+
actions: Dict[int, Dict[Union[str, int], ModifierAction]]
|
24
42
|
|
25
43
|
|
26
44
|
_translation_table = str.maketrans("", "", "_- ")
|
@@ -28,7 +46,7 @@ _translation_table = str.maketrans("", "", "_- ")
|
|
28
46
|
ROBOTCODE_MARKER = "robotcode:"
|
29
47
|
|
30
48
|
|
31
|
-
class
|
49
|
+
class ModifiersVisitor(Visitor):
|
32
50
|
|
33
51
|
def __init__(self) -> None:
|
34
52
|
super().__init__()
|
@@ -65,8 +83,8 @@ class DisablersVisitor(Visitor):
|
|
65
83
|
self._handle_statement_comments(node)
|
66
84
|
self.generic_visit(node)
|
67
85
|
|
68
|
-
def _parse_robotcode_disabler(self, comment: str) -> Dict[
|
69
|
-
result: Dict[
|
86
|
+
def _parse_robotcode_disabler(self, comment: str) -> Dict[ModifierAction, List[str]]:
|
87
|
+
result: Dict[ModifierAction, List[str]] = {}
|
70
88
|
|
71
89
|
comment = comment.strip()
|
72
90
|
m = ROBOTCODE_ACTION_AND_CODES_PATTERN.match(comment)
|
@@ -74,7 +92,8 @@ class DisablersVisitor(Visitor):
|
|
74
92
|
return result
|
75
93
|
|
76
94
|
for m in ROBOTCODE_ACTION_AND_CODES_PATTERN.finditer(comment):
|
77
|
-
|
95
|
+
action_str = m.group("action")
|
96
|
+
action = ModifierAction.from_str(action_str)
|
78
97
|
messages = m.group("codes")
|
79
98
|
result[action] = (
|
80
99
|
[m.strip().translate(_translation_table).lower() for m in messages.split(",")]
|
@@ -153,19 +172,36 @@ class DisablersVisitor(Visitor):
|
|
153
172
|
self.rules_and_codes.actions[i][code] = action
|
154
173
|
|
155
174
|
|
175
|
+
@dataclass
|
176
|
+
class DiagnosticModifiersConfig:
|
177
|
+
ignore: List[str] = field(default_factory=list)
|
178
|
+
error: List[str] = field(default_factory=list)
|
179
|
+
warning: List[str] = field(default_factory=list)
|
180
|
+
information: List[str] = field(default_factory=list)
|
181
|
+
hint: List[str] = field(default_factory=list)
|
182
|
+
|
183
|
+
|
156
184
|
class DiagnosticsModifier:
|
157
|
-
def __init__(self, model: AST) -> None:
|
185
|
+
def __init__(self, model: AST, config: Optional[DiagnosticModifiersConfig] = None) -> None:
|
186
|
+
self.config = config or DiagnosticModifiersConfig()
|
187
|
+
|
188
|
+
self.config.ignore = [i.translate(_translation_table).lower() for i in self.config.ignore]
|
189
|
+
self.config.error = [i.translate(_translation_table).lower() for i in self.config.error]
|
190
|
+
self.config.warning = [i.translate(_translation_table).lower() for i in self.config.warning]
|
191
|
+
self.config.information = [i.translate(_translation_table).lower() for i in self.config.information]
|
192
|
+
self.config.hint = [i.translate(_translation_table).lower() for i in self.config.hint]
|
193
|
+
|
158
194
|
self.model = model
|
159
195
|
|
160
196
|
@functools.cached_property
|
161
197
|
def rules_and_codes(self) -> RulesAndCodes:
|
162
|
-
visitor =
|
198
|
+
visitor = ModifiersVisitor()
|
163
199
|
visitor.visit(self.model)
|
164
200
|
return visitor.rules_and_codes
|
165
201
|
|
166
202
|
def modify_diagnostic(self, diagnostic: Diagnostic) -> Optional[Diagnostic]:
|
167
203
|
if diagnostic.code is not None:
|
168
|
-
code = (
|
204
|
+
code = orig_code = (
|
169
205
|
str(diagnostic.code).translate(_translation_table).lower()
|
170
206
|
if diagnostic.code is not None
|
171
207
|
else "unknowncode"
|
@@ -177,24 +213,51 @@ class DiagnosticsModifier:
|
|
177
213
|
code = "*"
|
178
214
|
lines = self.rules_and_codes.codes.get(code)
|
179
215
|
|
216
|
+
modified = False
|
180
217
|
if lines is not None and diagnostic.range.start.line in lines:
|
181
218
|
actions = self.rules_and_codes.actions.get(diagnostic.range.start.line)
|
182
219
|
if actions is not None:
|
183
220
|
action = actions.get(code)
|
184
221
|
if action is not None:
|
185
|
-
if action ==
|
222
|
+
if action == ModifierAction.IGNORE:
|
186
223
|
return None
|
187
|
-
if action ==
|
188
|
-
pass
|
189
|
-
elif action ==
|
224
|
+
if action == ModifierAction.RESET:
|
225
|
+
pass
|
226
|
+
elif action == ModifierAction.ERROR:
|
227
|
+
modified = True
|
190
228
|
diagnostic.severity = DiagnosticSeverity.ERROR
|
191
|
-
elif action ==
|
229
|
+
elif action == ModifierAction.WARNING:
|
230
|
+
modified = True
|
192
231
|
diagnostic.severity = DiagnosticSeverity.WARNING
|
193
|
-
elif action ==
|
232
|
+
elif action == ModifierAction.INFORMATION:
|
233
|
+
modified = True
|
194
234
|
diagnostic.severity = DiagnosticSeverity.INFORMATION
|
195
|
-
elif action ==
|
235
|
+
elif action == ModifierAction.HINT:
|
236
|
+
modified = True
|
196
237
|
diagnostic.severity = DiagnosticSeverity.HINT
|
197
238
|
|
239
|
+
if not modified:
|
240
|
+
if orig_code in self.config.ignore:
|
241
|
+
return None
|
242
|
+
if orig_code in self.config.error:
|
243
|
+
diagnostic.severity = DiagnosticSeverity.ERROR
|
244
|
+
elif orig_code in self.config.warning:
|
245
|
+
diagnostic.severity = DiagnosticSeverity.WARNING
|
246
|
+
elif orig_code in self.config.information:
|
247
|
+
diagnostic.severity = DiagnosticSeverity.INFORMATION
|
248
|
+
elif orig_code in self.config.hint:
|
249
|
+
diagnostic.severity = DiagnosticSeverity.HINT
|
250
|
+
elif "*" in self.config.hint:
|
251
|
+
diagnostic.severity = DiagnosticSeverity.HINT
|
252
|
+
elif "*" in self.config.information:
|
253
|
+
diagnostic.severity = DiagnosticSeverity.INFORMATION
|
254
|
+
elif "*" in self.config.warning:
|
255
|
+
diagnostic.severity = DiagnosticSeverity.WARNING
|
256
|
+
elif "*" in self.config.error:
|
257
|
+
diagnostic.severity = DiagnosticSeverity.ERROR
|
258
|
+
elif "*" in self.config.ignore:
|
259
|
+
return None
|
260
|
+
|
198
261
|
return diagnostic
|
199
262
|
|
200
263
|
def modify_diagnostics(self, diagnostics: List[Diagnostic]) -> List[Diagnostic]:
|
@@ -26,7 +26,7 @@ from robotcode.core.text_document import TextDocument
|
|
26
26
|
from robotcode.core.uri import Uri
|
27
27
|
from robotcode.core.utils.logging import LoggingDescriptor
|
28
28
|
from robotcode.core.workspace import Workspace, WorkspaceFolder
|
29
|
-
from robotcode.robot.diagnostics.diagnostics_modifier import DiagnosticsModifier
|
29
|
+
from robotcode.robot.diagnostics.diagnostics_modifier import DiagnosticModifiersConfig, DiagnosticsModifier
|
30
30
|
|
31
31
|
from ..config.model import RobotBaseProfile
|
32
32
|
from ..utils import get_robot_version
|
@@ -34,7 +34,13 @@ from ..utils.stubs import Languages
|
|
34
34
|
from .imports_manager import ImportsManager
|
35
35
|
from .library_doc import LibraryDoc
|
36
36
|
from .namespace import DocumentType, Namespace
|
37
|
-
from .workspace_config import
|
37
|
+
from .workspace_config import (
|
38
|
+
AnalysisDiagnosticModifiersConfig,
|
39
|
+
AnalysisRobotConfig,
|
40
|
+
CacheConfig,
|
41
|
+
RobotConfig,
|
42
|
+
WorkspaceAnalysisConfig,
|
43
|
+
)
|
38
44
|
|
39
45
|
|
40
46
|
class UnknownFileTypeError(Exception):
|
@@ -54,6 +60,7 @@ class DocumentsCacheHelper:
|
|
54
60
|
documents_manager: DocumentsManager,
|
55
61
|
file_watcher_manager: FileWatcherManagerBase,
|
56
62
|
robot_profile: Optional[RobotBaseProfile],
|
63
|
+
analysis_config: Optional[WorkspaceAnalysisConfig],
|
57
64
|
) -> None:
|
58
65
|
self.INITIALIZED_NAMESPACE = _CacheEntry()
|
59
66
|
|
@@ -62,6 +69,7 @@ class DocumentsCacheHelper:
|
|
62
69
|
self.file_watcher_manager = file_watcher_manager
|
63
70
|
|
64
71
|
self.robot_profile = robot_profile or RobotBaseProfile()
|
72
|
+
self.analysis_config = analysis_config or WorkspaceAnalysisConfig()
|
65
73
|
|
66
74
|
self._imports_managers_lock = threading.RLock()
|
67
75
|
self._imports_managers: weakref.WeakKeyDictionary[WorkspaceFolder, ImportsManager] = weakref.WeakKeyDictionary()
|
@@ -514,10 +522,10 @@ class DocumentsCacheHelper:
|
|
514
522
|
variables,
|
515
523
|
variable_files,
|
516
524
|
environment,
|
517
|
-
cache_config.ignored_libraries,
|
518
|
-
cache_config.ignored_variables,
|
519
|
-
cache_config.ignore_arguments_for_library,
|
520
|
-
analysis_config.global_library_search_order,
|
525
|
+
self.analysis_config.cache.ignored_libraries + cache_config.ignored_libraries,
|
526
|
+
self.analysis_config.cache.ignored_variables + cache_config.ignored_variables,
|
527
|
+
self.analysis_config.cache.ignore_arguments_for_library + cache_config.ignore_arguments_for_library,
|
528
|
+
self.analysis_config.robot.global_library_search_order + analysis_config.global_library_search_order,
|
521
529
|
cache_base_path,
|
522
530
|
)
|
523
531
|
|
@@ -583,4 +591,14 @@ class DocumentsCacheHelper:
|
|
583
591
|
return document.get_cache(self.__get_diagnostic_modifier)
|
584
592
|
|
585
593
|
def __get_diagnostic_modifier(self, document: TextDocument) -> DiagnosticsModifier:
|
586
|
-
|
594
|
+
modifiers_config = self.workspace.get_configuration(AnalysisDiagnosticModifiersConfig, document.uri)
|
595
|
+
return DiagnosticsModifier(
|
596
|
+
self.get_model(document, False),
|
597
|
+
DiagnosticModifiersConfig(
|
598
|
+
ignore=self.analysis_config.modifiers.ignore + modifiers_config.ignore,
|
599
|
+
error=self.analysis_config.modifiers.error + modifiers_config.error,
|
600
|
+
warning=self.analysis_config.modifiers.warning + modifiers_config.warning,
|
601
|
+
information=self.analysis_config.modifiers.information + modifiers_config.information,
|
602
|
+
hint=self.analysis_config.modifiers.hint + modifiers_config.hint,
|
603
|
+
),
|
604
|
+
)
|
@@ -160,7 +160,7 @@ class VariableMatcher:
|
|
160
160
|
return False
|
161
161
|
|
162
162
|
def __hash__(self) -> int:
|
163
|
-
return hash(self.
|
163
|
+
return hash(self.normalized_name)
|
164
164
|
|
165
165
|
def __str__(self) -> str:
|
166
166
|
return self.name
|
@@ -252,7 +252,7 @@ class BuiltInVariableDefinition(VariableDefinition):
|
|
252
252
|
|
253
253
|
@single_call
|
254
254
|
def __hash__(self) -> int:
|
255
|
-
return hash((type(self), self.name, self.type))
|
255
|
+
return hash((type(self), self.name, self.type, None, None))
|
256
256
|
|
257
257
|
|
258
258
|
@dataclass
|
@@ -64,6 +64,7 @@ from .library_doc import (
|
|
64
64
|
get_variables_doc,
|
65
65
|
is_library_by_path,
|
66
66
|
is_variables_by_path,
|
67
|
+
replace_variables_scalar,
|
67
68
|
resolve_args,
|
68
69
|
resolve_variable,
|
69
70
|
)
|
@@ -905,7 +906,8 @@ class ImportsManager:
|
|
905
906
|
):
|
906
907
|
self._logger.debug(
|
907
908
|
lambda: f"Ignore library {result.name or '' if result is not None else ''}"
|
908
|
-
f" {result.origin or '' if result is not None else ''} for caching."
|
909
|
+
f" {result.origin or '' if result is not None else ''} for caching.",
|
910
|
+
context_name="import",
|
909
911
|
)
|
910
912
|
return None, import_name, ignore_arguments
|
911
913
|
|
@@ -1143,9 +1145,7 @@ class ImportsManager:
|
|
1143
1145
|
base_dir: str,
|
1144
1146
|
variables: Optional[Dict[str, Any]] = None,
|
1145
1147
|
) -> LibraryDoc:
|
1146
|
-
meta,
|
1147
|
-
|
1148
|
-
self._logger.debug(lambda: f"Load Library {source}{args!r}")
|
1148
|
+
meta, _source, ignore_arguments = self.get_library_meta(name, base_dir, variables)
|
1149
1149
|
|
1150
1150
|
if meta is not None and not meta.has_errors:
|
1151
1151
|
meta_file = Path(self.lib_doc_cache_path, meta.filepath_base + ".meta.json")
|
@@ -1219,7 +1219,7 @@ class ImportsManager:
|
|
1219
1219
|
|
1220
1220
|
meta_file.write_text(as_json(meta), "utf-8")
|
1221
1221
|
else:
|
1222
|
-
self._logger.debug(lambda: f"Skip caching library {name}{args!r}")
|
1222
|
+
self._logger.debug(lambda: f"Skip caching library {name}{args!r}", context_name="import")
|
1223
1223
|
except (SystemExit, KeyboardInterrupt):
|
1224
1224
|
raise
|
1225
1225
|
except BaseException as e:
|
@@ -1236,37 +1236,37 @@ class ImportsManager:
|
|
1236
1236
|
sentinel: Any = None,
|
1237
1237
|
variables: Optional[Dict[str, Any]] = None,
|
1238
1238
|
) -> LibraryDoc:
|
1239
|
+
with self._logger.measure_time(lambda: f"loading library {name}{args!r}", context_name="import"):
|
1240
|
+
source = self.find_library(name, base_dir, variables)
|
1239
1241
|
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
ignore_reference=sentinel is None,
|
1261
|
-
)
|
1242
|
+
resolved_args = resolve_args(
|
1243
|
+
args,
|
1244
|
+
str(self.root_folder),
|
1245
|
+
base_dir,
|
1246
|
+
self.get_resolvable_command_line_variables(),
|
1247
|
+
variables,
|
1248
|
+
)
|
1249
|
+
entry_key = _LibrariesEntryKey(source, resolved_args)
|
1250
|
+
|
1251
|
+
with self._libaries_lock:
|
1252
|
+
if entry_key not in self._libaries:
|
1253
|
+
self._libaries[entry_key] = _LibrariesEntry(
|
1254
|
+
self,
|
1255
|
+
name,
|
1256
|
+
args,
|
1257
|
+
str(self.root_folder),
|
1258
|
+
base_dir,
|
1259
|
+
self._get_library_libdoc_handler(variables),
|
1260
|
+
ignore_reference=sentinel is None,
|
1261
|
+
)
|
1262
1262
|
|
1263
|
-
|
1263
|
+
entry = self._libaries[entry_key]
|
1264
1264
|
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1265
|
+
if not entry.ignore_reference and sentinel is not None and sentinel not in entry.references:
|
1266
|
+
weakref.finalize(sentinel, self.__remove_library_entry, entry_key, entry)
|
1267
|
+
entry.references.add(sentinel)
|
1268
1268
|
|
1269
|
-
|
1269
|
+
return entry.get_libdoc()
|
1270
1270
|
|
1271
1271
|
@_logger.call
|
1272
1272
|
def get_libdoc_from_model(
|
@@ -1313,7 +1313,7 @@ class ImportsManager:
|
|
1313
1313
|
resolve_variables: bool = True,
|
1314
1314
|
resolve_command_line_vars: bool = True,
|
1315
1315
|
) -> VariablesDoc:
|
1316
|
-
meta,
|
1316
|
+
meta, _source = self.get_variables_meta(
|
1317
1317
|
name,
|
1318
1318
|
base_dir,
|
1319
1319
|
variables,
|
@@ -1321,7 +1321,6 @@ class ImportsManager:
|
|
1321
1321
|
resolve_command_line_vars=resolve_command_line_vars,
|
1322
1322
|
)
|
1323
1323
|
|
1324
|
-
self._logger.debug(lambda: f"Load variables {source}{args!r}")
|
1325
1324
|
if meta is not None:
|
1326
1325
|
meta_file = Path(
|
1327
1326
|
self.variables_doc_cache_path,
|
@@ -1391,7 +1390,7 @@ class ImportsManager:
|
|
1391
1390
|
raise RuntimeError(f"Cannot write spec file for variables '{name}' to '{spec_file}'") from e
|
1392
1391
|
meta_file.write_text(as_json(meta), "utf-8")
|
1393
1392
|
else:
|
1394
|
-
self._logger.debug(lambda: f"Skip caching variables {name}{args!r}")
|
1393
|
+
self._logger.debug(lambda: f"Skip caching variables {name}{args!r}", context_name="import")
|
1395
1394
|
except (SystemExit, KeyboardInterrupt):
|
1396
1395
|
raise
|
1397
1396
|
except BaseException as e:
|
@@ -1410,39 +1409,40 @@ class ImportsManager:
|
|
1410
1409
|
resolve_variables: bool = True,
|
1411
1410
|
resolve_command_line_vars: bool = True,
|
1412
1411
|
) -> VariablesDoc:
|
1413
|
-
|
1414
|
-
|
1415
|
-
if args:
|
1416
|
-
resolved_args = resolve_args(
|
1417
|
-
args,
|
1418
|
-
str(self.root_folder),
|
1419
|
-
base_dir,
|
1420
|
-
self.get_resolvable_command_line_variables() if resolve_command_line_vars else None,
|
1421
|
-
variables,
|
1422
|
-
)
|
1423
|
-
else:
|
1424
|
-
resolved_args = ()
|
1412
|
+
with self._logger.measure_time(lambda: f"getting libdoc for variables import {name}", context_name="import"):
|
1413
|
+
source = self.find_variables(name, base_dir, variables, resolve_variables, resolve_command_line_vars)
|
1425
1414
|
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
if entry_key not in self._variables:
|
1430
|
-
self._variables[entry_key] = _VariablesEntry(
|
1431
|
-
name,
|
1432
|
-
resolved_args,
|
1415
|
+
if args:
|
1416
|
+
resolved_args = resolve_args(
|
1417
|
+
args,
|
1433
1418
|
str(self.root_folder),
|
1434
1419
|
base_dir,
|
1435
|
-
self,
|
1436
|
-
|
1420
|
+
self.get_resolvable_command_line_variables() if resolve_command_line_vars else None,
|
1421
|
+
variables,
|
1437
1422
|
)
|
1423
|
+
else:
|
1424
|
+
resolved_args = ()
|
1425
|
+
|
1426
|
+
entry_key = _VariablesEntryKey(source, resolved_args)
|
1427
|
+
|
1428
|
+
with self._variables_lock:
|
1429
|
+
if entry_key not in self._variables:
|
1430
|
+
self._variables[entry_key] = _VariablesEntry(
|
1431
|
+
name,
|
1432
|
+
resolved_args,
|
1433
|
+
str(self.root_folder),
|
1434
|
+
base_dir,
|
1435
|
+
self,
|
1436
|
+
self._get_variables_libdoc_handler(variables, resolve_variables, resolve_command_line_vars),
|
1437
|
+
)
|
1438
1438
|
|
1439
|
-
|
1439
|
+
entry = self._variables[entry_key]
|
1440
1440
|
|
1441
|
-
|
1442
|
-
|
1443
|
-
|
1441
|
+
if sentinel is not None and sentinel not in entry.references:
|
1442
|
+
entry.references.add(sentinel)
|
1443
|
+
weakref.finalize(sentinel, self.__remove_variables_entry, entry_key, entry)
|
1444
1444
|
|
1445
|
-
|
1445
|
+
return entry.get_libdoc()
|
1446
1446
|
|
1447
1447
|
@_logger.call
|
1448
1448
|
def _get_entry_for_resource_import(
|
@@ -1455,7 +1455,7 @@ class ImportsManager:
|
|
1455
1455
|
source = self.find_resource(name, base_dir, variables=variables)
|
1456
1456
|
|
1457
1457
|
def _get_document() -> TextDocument:
|
1458
|
-
self._logger.debug(lambda: f"Load resource {name} from source {source}")
|
1458
|
+
self._logger.debug(lambda: f"Load resource {name} from source {source}", context_name="import")
|
1459
1459
|
|
1460
1460
|
source_path = normalized_path(Path(source))
|
1461
1461
|
extension = source_path.suffix
|
@@ -1488,9 +1488,10 @@ class ImportsManager:
|
|
1488
1488
|
sentinel: Any = None,
|
1489
1489
|
variables: Optional[Dict[str, Any]] = None,
|
1490
1490
|
) -> Tuple["Namespace", LibraryDoc]:
|
1491
|
-
|
1491
|
+
with self._logger.measure_time(lambda: f"getting namespace and libdoc for {name}", context_name="import"):
|
1492
|
+
entry = self._get_entry_for_resource_import(name, base_dir, sentinel, variables)
|
1492
1493
|
|
1493
|
-
|
1494
|
+
return entry.get_namespace(), entry.get_libdoc()
|
1494
1495
|
|
1495
1496
|
def get_namespace_for_resource_import(
|
1496
1497
|
self,
|
@@ -1572,3 +1573,17 @@ class ImportsManager:
|
|
1572
1573
|
self.get_resolvable_command_line_variables(),
|
1573
1574
|
variables,
|
1574
1575
|
)
|
1576
|
+
|
1577
|
+
def replace_variables_scalar(
|
1578
|
+
self,
|
1579
|
+
scalar: str,
|
1580
|
+
base_dir: str = ".",
|
1581
|
+
variables: Optional[Dict[str, Any]] = None,
|
1582
|
+
) -> Any:
|
1583
|
+
return replace_variables_scalar(
|
1584
|
+
scalar,
|
1585
|
+
str(self.root_folder),
|
1586
|
+
base_dir,
|
1587
|
+
self.get_resolvable_command_line_variables(),
|
1588
|
+
variables,
|
1589
|
+
)
|
@@ -45,12 +45,8 @@ from robot.parsing.lexer.tokens import Token
|
|
45
45
|
from robot.parsing.lexer.tokens import Token as RobotToken
|
46
46
|
from robot.parsing.model.blocks import Keyword
|
47
47
|
from robot.parsing.model.statements import Arguments, KeywordName
|
48
|
-
from robot.running.arguments.argumentresolver import
|
49
|
-
|
50
|
-
DictToKwargs,
|
51
|
-
NamedArgumentResolver,
|
52
|
-
VariableReplacer,
|
53
|
-
)
|
48
|
+
from robot.running.arguments.argumentresolver import ArgumentResolver, DictToKwargs, NamedArgumentResolver
|
49
|
+
from robot.running.arguments.argumentresolver import VariableReplacer as ArgumentsVariableReplacer
|
54
50
|
from robot.running.arguments.argumentspec import ArgInfo
|
55
51
|
from robot.running.arguments.argumentspec import (
|
56
52
|
ArgumentSpec as RobotArgumentSpec,
|
@@ -64,6 +60,7 @@ from robot.utils.robotpath import find_file as robot_find_file
|
|
64
60
|
from robot.variables import Variables
|
65
61
|
from robot.variables.filesetter import PythonImporter, YamlImporter
|
66
62
|
from robot.variables.finders import VariableFinder
|
63
|
+
from robot.variables.replacer import VariableReplacer
|
67
64
|
from robot.variables.search import contains_variable
|
68
65
|
from robotcode.core.lsp.types import Position, Range
|
69
66
|
from robotcode.core.utils.path import normalized_path
|
@@ -578,9 +575,9 @@ class ArgumentSpec:
|
|
578
575
|
|
579
576
|
positional, named = MyNamedArgumentResolver(self.__robot_arguments).resolve(arguments, variables)
|
580
577
|
if get_robot_version() < (7, 0):
|
581
|
-
positional, named =
|
578
|
+
positional, named = ArgumentsVariableReplacer(resolve_variables_until).replace(positional, named, variables)
|
582
579
|
else:
|
583
|
-
positional, named =
|
580
|
+
positional, named = ArgumentsVariableReplacer(self.__robot_arguments, resolve_variables_until).replace(
|
584
581
|
positional, named, variables
|
585
582
|
)
|
586
583
|
positional, named = DictToKwargs(self.__robot_arguments, dict_to_kwargs).handle(positional, named)
|
@@ -1585,6 +1582,26 @@ def resolve_variable(
|
|
1585
1582
|
return name.replace("\\", "\\\\")
|
1586
1583
|
|
1587
1584
|
|
1585
|
+
def replace_variables_scalar(
|
1586
|
+
scalar: str,
|
1587
|
+
working_dir: str = ".",
|
1588
|
+
base_dir: str = ".",
|
1589
|
+
command_line_variables: Optional[Dict[str, Optional[Any]]] = None,
|
1590
|
+
variables: Optional[Dict[str, Optional[Any]]] = None,
|
1591
|
+
) -> Any:
|
1592
|
+
|
1593
|
+
_update_env(working_dir)
|
1594
|
+
|
1595
|
+
if contains_variable(scalar, "$@&%"):
|
1596
|
+
robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
|
1597
|
+
if get_robot_version() >= (6, 1):
|
1598
|
+
return VariableReplacer(robot_variables).replace_scalar(scalar.replace("\\", "\\\\"))
|
1599
|
+
|
1600
|
+
return VariableReplacer(robot_variables.store).replace_scalar(scalar.replace("\\", "\\\\"))
|
1601
|
+
|
1602
|
+
return scalar.replace("\\", "\\\\")
|
1603
|
+
|
1604
|
+
|
1588
1605
|
@contextmanager
|
1589
1606
|
def _std_capture() -> Iterator[io.StringIO]:
|
1590
1607
|
old__stdout__ = sys.__stdout__
|