robotcode-robot 0.91.0__py3-none-any.whl → 0.93.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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], str]]
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 DisablersVisitor(Visitor):
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[str, List[str]]:
69
- result: Dict[str, List[str]] = {}
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
- action = m.group("action")
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 = DisablersVisitor()
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 == "ignore":
222
+ if action == ModifierAction.IGNORE:
186
223
  return None
187
- if action == "reset":
188
- pass # do nothing
189
- elif action == "error":
224
+ if action == ModifierAction.RESET:
225
+ pass
226
+ elif action == ModifierAction.ERROR:
227
+ modified = True
190
228
  diagnostic.severity = DiagnosticSeverity.ERROR
191
- elif action == "warn":
229
+ elif action == ModifierAction.WARNING:
230
+ modified = True
192
231
  diagnostic.severity = DiagnosticSeverity.WARNING
193
- elif action == "information":
232
+ elif action == ModifierAction.INFORMATION:
233
+ modified = True
194
234
  diagnostic.severity = DiagnosticSeverity.INFORMATION
195
- elif action == "hint":
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 AnalysisRobotConfig, CacheConfig, RobotConfig
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
- return DiagnosticsModifier(self.get_model(document, False))
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.name)
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, source, ignore_arguments = self.get_library_meta(name, base_dir, variables)
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
- source = self.find_library(name, base_dir, variables)
1241
-
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
- )
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
- entry = self._libaries[entry_key]
1263
+ entry = self._libaries[entry_key]
1264
1264
 
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)
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
- return entry.get_libdoc()
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, source = self.get_variables_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
- source = self.find_variables(name, base_dir, variables, resolve_variables, resolve_command_line_vars)
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
- 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,
1415
+ if args:
1416
+ resolved_args = resolve_args(
1417
+ args,
1433
1418
  str(self.root_folder),
1434
1419
  base_dir,
1435
- self,
1436
- self._get_variables_libdoc_handler(variables, resolve_variables, resolve_command_line_vars),
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
- entry = self._variables[entry_key]
1439
+ entry = self._variables[entry_key]
1440
1440
 
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)
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
- return entry.get_libdoc()
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
- entry = self._get_entry_for_resource_import(name, base_dir, sentinel, variables)
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
- return entry.get_namespace(), entry.get_libdoc()
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
- ArgumentResolver,
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 = VariableReplacer(resolve_variables_until).replace(positional, named, variables)
578
+ positional, named = ArgumentsVariableReplacer(resolve_variables_until).replace(positional, named, variables)
582
579
  else:
583
- positional, named = VariableReplacer(self.__robot_arguments, resolve_variables_until).replace(
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__