robotcode-robot 0.82.0__py3-none-any.whl → 0.82.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
1
- __version__ = "0.82.0"
1
+ __version__ = "0.82.2"
@@ -258,6 +258,7 @@ class ModelHelper:
258
258
  nodes: Optional[List[ast.AST]],
259
259
  position: Optional[Position] = None,
260
260
  skip_commandline_variables: bool = False,
261
+ skip_local_variables: bool = False,
261
262
  return_not_found: bool = False,
262
263
  ) -> Iterator[Tuple[Token, VariableDefinition]]:
263
264
  variable_started = False
@@ -270,6 +271,7 @@ class ModelHelper:
270
271
  nodes,
271
272
  position,
272
273
  skip_commandline_variables=skip_commandline_variables,
274
+ skip_local_variables=skip_local_variables,
273
275
  ignore_error=True,
274
276
  )
275
277
  sub_token = Token(
@@ -376,6 +378,7 @@ class ModelHelper:
376
378
  nodes: Optional[List[ast.AST]],
377
379
  position: Optional[Position] = None,
378
380
  skip_commandline_variables: bool = False,
381
+ skip_local_variables: bool = False,
379
382
  return_not_found: bool = False,
380
383
  ) -> Iterator[Tuple[Token, VariableDefinition]]:
381
384
  def is_number(name: str) -> bool:
@@ -405,6 +408,7 @@ class ModelHelper:
405
408
  nodes,
406
409
  position,
407
410
  skip_commandline_variables=skip_commandline_variables,
411
+ skip_local_variables=skip_local_variables,
408
412
  return_not_found=return_not_found,
409
413
  ):
410
414
  yield v
@@ -461,6 +465,7 @@ class ModelHelper:
461
465
  nodes,
462
466
  position,
463
467
  skip_commandline_variables=skip_commandline_variables,
468
+ skip_local_variables=skip_local_variables,
464
469
  ignore_error=True,
465
470
  )
466
471
  if var is not None:
@@ -485,6 +490,7 @@ class ModelHelper:
485
490
  nodes,
486
491
  position,
487
492
  skip_commandline_variables=skip_commandline_variables,
493
+ skip_local_variables=skip_local_variables,
488
494
  ignore_error=True,
489
495
  )
490
496
  sub_sub_token = Token(
@@ -26,13 +26,8 @@ from typing import (
26
26
  from robot.errors import VariableError
27
27
  from robot.libraries import STDLIBS
28
28
  from robot.parsing.lexer.tokens import Token
29
- from robot.parsing.model.blocks import (
30
- Keyword,
31
- SettingSection,
32
- TestCase,
33
- VariableSection,
34
- )
35
- from robot.parsing.model.statements import Arguments, Statement
29
+ from robot.parsing.model.blocks import Keyword, SettingSection, TestCase, VariableSection
30
+ from robot.parsing.model.statements import Arguments, Fixture, Statement, Timeout
36
31
  from robot.parsing.model.statements import LibraryImport as RobotLibraryImport
37
32
  from robot.parsing.model.statements import ResourceImport as RobotResourceImport
38
33
  from robot.parsing.model.statements import (
@@ -182,7 +177,7 @@ class VariablesVisitor(Visitor):
182
177
  )
183
178
 
184
179
 
185
- class BlockVariableVisitor(Visitor):
180
+ class VariableVisitorBase(Visitor):
186
181
  def __init__(
187
182
  self,
188
183
  namespace: "Namespace",
@@ -198,7 +193,79 @@ class BlockVariableVisitor(Visitor):
198
193
 
199
194
  self._results: Dict[str, VariableDefinition] = {}
200
195
  self.current_kw_doc: Optional[KeywordDoc] = None
196
+ self.current_kw: Optional[Keyword] = None
197
+
198
+ def get_variable_token(self, token: Token) -> Optional[Token]:
199
+ return next(
200
+ (
201
+ v
202
+ for v in itertools.dropwhile(
203
+ lambda t: t.type in Token.NON_DATA_TOKENS,
204
+ tokenize_variables(token, ignore_errors=True, extra_types={Token.VARIABLE}),
205
+ )
206
+ if v.type == Token.VARIABLE
207
+ ),
208
+ None,
209
+ )
210
+
211
+
212
+ class ArgumentVisitor(VariableVisitorBase):
213
+ def __init__(
214
+ self,
215
+ namespace: "Namespace",
216
+ nodes: Optional[List[ast.AST]],
217
+ position: Optional[Position],
218
+ in_args: bool,
219
+ current_kw_doc: Optional[KeywordDoc],
220
+ ) -> None:
221
+ super().__init__(namespace, nodes, position, in_args)
222
+
223
+ self.current_kw_doc: Optional[KeywordDoc] = current_kw_doc
224
+
225
+ def get(self, model: ast.AST) -> Dict[str, VariableDefinition]:
226
+ self._results = {}
227
+
228
+ self.visit(model)
229
+
230
+ return self._results
231
+
232
+ def visit_Arguments(self, node: Statement) -> None: # noqa: N802
233
+ args: List[str] = []
234
+
235
+ arguments = node.get_tokens(Token.ARGUMENT)
236
+
237
+ for argument_token in arguments:
238
+ try:
239
+ argument = self.get_variable_token(argument_token)
240
+
241
+ if argument is not None and argument.value != "@{}":
242
+ if (
243
+ self.in_args
244
+ and self.position is not None
245
+ and self.position in range_from_token(argument_token)
246
+ and self.position > range_from_token(argument).end
247
+ ):
248
+ break
249
+
250
+ if argument.value not in args:
251
+ args.append(argument.value)
252
+ arg_def = ArgumentDefinition(
253
+ name=argument.value,
254
+ name_token=strip_variable_token(argument),
255
+ line_no=argument.lineno,
256
+ col_offset=argument.col_offset,
257
+ end_line_no=argument.lineno,
258
+ end_col_offset=argument.end_col_offset,
259
+ source=self.namespace.source,
260
+ keyword_doc=self.current_kw_doc,
261
+ )
262
+ self._results[argument.value] = arg_def
263
+
264
+ except VariableError:
265
+ pass
201
266
 
267
+
268
+ class OnlyArgumentsVisitor(VariableVisitorBase):
202
269
  def get(self, model: ast.AST) -> List[VariableDefinition]:
203
270
  self._results = {}
204
271
 
@@ -211,9 +278,11 @@ class BlockVariableVisitor(Visitor):
211
278
  super().visit(node)
212
279
 
213
280
  def visit_Keyword(self, node: ast.AST) -> None: # noqa: N802
281
+ self.current_kw = cast(Keyword, node)
214
282
  try:
215
283
  self.generic_visit(node)
216
284
  finally:
285
+ self.current_kw = None
217
286
  self.current_kw_doc = None
218
287
 
219
288
  def visit_KeywordName(self, node: Statement) -> None: # noqa: N802
@@ -248,53 +317,15 @@ class BlockVariableVisitor(Visitor):
248
317
  keyword_doc=self.current_kw_doc,
249
318
  )
250
319
 
251
- def get_variable_token(self, token: Token) -> Optional[Token]:
252
- return next(
253
- (
254
- v
255
- for v in itertools.dropwhile(
256
- lambda t: t.type in Token.NON_DATA_TOKENS,
257
- tokenize_variables(token, ignore_errors=True, extra_types={Token.VARIABLE}),
258
- )
259
- if v.type == Token.VARIABLE
260
- ),
261
- None,
262
- )
263
-
264
- def visit_Arguments(self, node: Statement) -> None: # noqa: N802
265
- args: List[str] = []
320
+ if self.current_kw is not None:
321
+ args = ArgumentVisitor(
322
+ self.namespace, self.nodes, self.position, self.in_args, self.current_kw_doc
323
+ ).get(self.current_kw)
324
+ if args:
325
+ self._results.update(args)
266
326
 
267
- arguments = node.get_tokens(Token.ARGUMENT)
268
327
 
269
- for argument_token in arguments:
270
- try:
271
- argument = self.get_variable_token(argument_token)
272
-
273
- if argument is not None and argument.value != "@{}":
274
- if (
275
- self.in_args
276
- and self.position is not None
277
- and self.position in range_from_token(argument_token)
278
- and self.position > range_from_token(argument).end
279
- ):
280
- break
281
-
282
- if argument.value not in args:
283
- args.append(argument.value)
284
- arg_def = ArgumentDefinition(
285
- name=argument.value,
286
- name_token=strip_variable_token(argument),
287
- line_no=argument.lineno,
288
- col_offset=argument.col_offset,
289
- end_line_no=argument.lineno,
290
- end_col_offset=argument.end_col_offset,
291
- source=self.namespace.source,
292
- keyword_doc=self.current_kw_doc,
293
- )
294
- self._results[argument.value] = arg_def
295
-
296
- except VariableError:
297
- pass
328
+ class BlockVariableVisitor(OnlyArgumentsVisitor):
298
329
 
299
330
  def visit_ExceptHeader(self, node: Statement) -> None: # noqa: N802
300
331
  variables = node.get_tokens(Token.VARIABLE)[:1]
@@ -990,10 +1021,12 @@ class Namespace:
990
1021
  nodes: Optional[List[ast.AST]] = None,
991
1022
  position: Optional[Position] = None,
992
1023
  skip_commandline_variables: bool = False,
1024
+ skip_local_variables: bool = False,
993
1025
  ) -> Iterator[Tuple[VariableMatcher, VariableDefinition]]:
994
1026
  yielded: Dict[VariableMatcher, VariableDefinition] = {}
995
1027
 
996
1028
  test_or_keyword = None
1029
+ test_or_keyword_nodes = None
997
1030
 
998
1031
  if nodes:
999
1032
  test_or_keyword_nodes = list(
@@ -1004,18 +1037,23 @@ class Namespace:
1004
1037
  )
1005
1038
  test_or_keyword = test_or_keyword_nodes[0] if test_or_keyword_nodes else None
1006
1039
 
1040
+ in_args = isinstance(test_or_keyword_nodes[-1], Arguments) if test_or_keyword_nodes else False
1041
+ only_args = (
1042
+ isinstance(test_or_keyword_nodes[-1], (Arguments, Fixture, Timeout)) if test_or_keyword_nodes else False
1043
+ )
1044
+
1007
1045
  for var in chain(
1008
1046
  *[
1009
1047
  (
1010
1048
  (
1011
- BlockVariableVisitor(
1049
+ (OnlyArgumentsVisitor if only_args else BlockVariableVisitor)(
1012
1050
  self,
1013
1051
  nodes,
1014
1052
  position,
1015
- isinstance(test_or_keyword_nodes[-1], Arguments) if nodes else False,
1053
+ in_args,
1016
1054
  ).get(test_or_keyword)
1017
1055
  )
1018
- if test_or_keyword is not None
1056
+ if test_or_keyword is not None and not skip_local_variables
1019
1057
  else []
1020
1058
  )
1021
1059
  ],
@@ -1081,6 +1119,7 @@ class Namespace:
1081
1119
  nodes: Optional[List[ast.AST]] = None,
1082
1120
  position: Optional[Position] = None,
1083
1121
  skip_commandline_variables: bool = False,
1122
+ skip_local_variables: bool = False,
1084
1123
  ignore_error: bool = False,
1085
1124
  ) -> Optional[VariableDefinition]:
1086
1125
  self.ensure_initialized()
@@ -1105,6 +1144,7 @@ class Namespace:
1105
1144
  nodes,
1106
1145
  position,
1107
1146
  skip_commandline_variables=skip_commandline_variables,
1147
+ skip_local_variables=skip_local_variables,
1108
1148
  ):
1109
1149
  if matcher == m:
1110
1150
  return v
@@ -12,12 +12,14 @@ from robot.parsing.lexer.tokens import Token
12
12
  from robot.parsing.model.blocks import Keyword, TestCase
13
13
  from robot.parsing.model.statements import (
14
14
  Arguments,
15
+ DefaultTags,
15
16
  DocumentationOrMetadata,
16
17
  Fixture,
17
18
  KeywordCall,
18
19
  LibraryImport,
19
20
  ResourceImport,
20
21
  Statement,
22
+ Tags,
21
23
  Template,
22
24
  TemplateArguments,
23
25
  TestCaseName,
@@ -70,9 +72,35 @@ from .namespace import KeywordFinder, Namespace
70
72
 
71
73
  if get_robot_version() < (7, 0):
72
74
  from robot.variables.search import VariableIterator
75
+
76
+ VARIABLE_NOT_FOUND_HINT_TYPES: Tuple[Any, ...] = (
77
+ DocumentationOrMetadata,
78
+ TestCaseName,
79
+ Tags,
80
+ robot.parsing.model.statements.ForceTags,
81
+ DefaultTags,
82
+ )
83
+
84
+ IN_SETTING_TYPES: Tuple[Any, ...] = (
85
+ DocumentationOrMetadata,
86
+ Tags,
87
+ robot.parsing.model.statements.ForceTags,
88
+ DefaultTags,
89
+ Template,
90
+ )
73
91
  else:
74
92
  from robot.variables.search import VariableMatches
75
93
 
94
+ VARIABLE_NOT_FOUND_HINT_TYPES = (
95
+ DocumentationOrMetadata,
96
+ TestCaseName,
97
+ Tags,
98
+ robot.parsing.model.statements.TestTags,
99
+ DefaultTags,
100
+ )
101
+
102
+ IN_SETTING_TYPES = (DocumentationOrMetadata, Tags, robot.parsing.model.statements.TestTags, DefaultTags, Template)
103
+
76
104
 
77
105
  @dataclass
78
106
  class AnalyzerResult:
@@ -266,10 +294,10 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
266
294
 
267
295
  self.node_stack.append(node)
268
296
  try:
297
+ in_setting = isinstance(node, IN_SETTING_TYPES)
298
+
269
299
  severity = (
270
- DiagnosticSeverity.HINT
271
- if isinstance(node, (DocumentationOrMetadata, TestCaseName))
272
- else DiagnosticSeverity.ERROR
300
+ DiagnosticSeverity.HINT if isinstance(node, VARIABLE_NOT_FOUND_HINT_TYPES) else DiagnosticSeverity.ERROR
273
301
  )
274
302
 
275
303
  if isinstance(node, KeywordCall) and node.keyword:
@@ -295,6 +323,7 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
295
323
  self.node_stack,
296
324
  range_from_token(token).start,
297
325
  skip_commandline_variables=False,
326
+ skip_local_variables=in_setting,
298
327
  return_not_found=True,
299
328
  ):
300
329
  if isinstance(var, VariableNotFoundDefinition):
@@ -380,6 +409,7 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
380
409
  self.node_stack,
381
410
  range_from_token(token).start,
382
411
  skip_commandline_variables=False,
412
+ skip_local_variables=in_setting,
383
413
  return_not_found=True,
384
414
  ):
385
415
  if isinstance(var, VariableNotFoundDefinition):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: robotcode-robot
3
- Version: 0.82.0
3
+ Version: 0.82.2
4
4
  Summary: Support classes for RobotCode for handling Robot Framework projects.
5
5
  Project-URL: Homepage, https://robotcode.io
6
6
  Project-URL: Donate, https://opencollective.com/robotcode
@@ -26,7 +26,7 @@ Classifier: Topic :: Utilities
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.8
28
28
  Requires-Dist: platformdirs<4.2.0,>=3.2.0
29
- Requires-Dist: robotcode-core==0.82.0
29
+ Requires-Dist: robotcode-core==0.82.2
30
30
  Requires-Dist: robotframework>=4.1.0
31
31
  Requires-Dist: tomli>=1.1.0; python_version < '3.11'
32
32
  Description-Content-Type: text/markdown
@@ -1,5 +1,5 @@
1
1
  robotcode/robot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/robot/__version__.py,sha256=3E7u1ATSjtoHo9Pq3zuZICzm_iPH64qoru2bGBZuNbw,23
2
+ robotcode/robot/__version__.py,sha256=RTYfZgQQ2I7IHQ7CnMLKfzWJLJYwV_HoEeJ8bvw2WlY,23
3
3
  robotcode/robot/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
4
4
  robotcode/robot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  robotcode/robot/config/loader.py,sha256=LpGqJAdysvVSZpccW-Il52xn9RMBBb9X94emlBY7zCc,6077
@@ -11,9 +11,9 @@ robotcode/robot/diagnostics/entities.py,sha256=CrjhLHHwKCCE3YI_dcjoZADJz1urm0VGb
11
11
  robotcode/robot/diagnostics/errors.py,sha256=VavgWYuHoW5sTT16j2rl9hxMhWxBKNSFsNmHWPzARQQ,1413
12
12
  robotcode/robot/diagnostics/imports_manager.py,sha256=qE__lm0Hsj3R0gUauXRmbWJPYihNjk3O-c5hcICGQjc,56251
13
13
  robotcode/robot/diagnostics/library_doc.py,sha256=sLENYhMoq5IvYgd0jUhVpRkRTvY9IfTotlthLUUO0vY,97124
14
- robotcode/robot/diagnostics/model_helper.py,sha256=3-6lZluPQaT9KstHLfV0jsRUAjTfrkUOomSXiMPKoQg,29868
15
- robotcode/robot/diagnostics/namespace.py,sha256=yerha8VmX_01h8Ga7MaH4wRVk1waVQ4pJfPu55ohcYU,89792
16
- robotcode/robot/diagnostics/namespace_analyzer.py,sha256=tElI2NzcCRnsvPqv7wYaV2p5E22VyqEwQQ90FOOjadI,50086
14
+ robotcode/robot/diagnostics/model_helper.py,sha256=_5ixKKMrb-nY-uvV8_WjJ1rlNlz7gT7kHM5NYi_hjVg,30232
15
+ robotcode/robot/diagnostics/namespace.py,sha256=OlhhK1RH4ZFGXZEerFQIzye0ddAq8V-W0cCsxYg6tdc,91315
16
+ robotcode/robot/diagnostics/namespace_analyzer.py,sha256=PWZjpLdn-9GCpp4L4dKxVF2B1hxzSEdDzBNUw2Lp51A,50937
17
17
  robotcode/robot/diagnostics/workspace_config.py,sha256=lWNq1KmGGJ9cHFNHn0QTCBHHzgz4AewTw0l-W4TKrj0,1803
18
18
  robotcode/robot/utils/__init__.py,sha256=OjNPMn_XSnfaMCyKd8Kmq6vlRt6mIGlzW4qiiD3ykUg,447
19
19
  robotcode/robot/utils/ast.py,sha256=N7PobxXjpPWwv6UBa-GBn5wn6RAsiRm8unP6UZt0P6M,10193
@@ -23,7 +23,7 @@ robotcode/robot/utils/robot_path.py,sha256=qKBh1cEnReBBLKkWu4gB9EzM-scAwE4xJc1m6
23
23
  robotcode/robot/utils/stubs.py,sha256=6-DMI_CQVJHDgG13t-zINKGCRb_Q7MQPm0_AkfhAEvE,748
24
24
  robotcode/robot/utils/variables.py,sha256=fEl8S37lb_mD4hn2MZRAlkiuLGBjAOeZVK0r2o2CfPw,742
25
25
  robotcode/robot/utils/visitor.py,sha256=uYLqEhGPmzWKWI3SSrmCaYMwtKvNShvbiPZ4b3FavX8,3241
26
- robotcode_robot-0.82.0.dist-info/METADATA,sha256=tolbKF_209BXd1oEnPJYGb3EXqx4n9bvKBp-lWuu-gI,2240
27
- robotcode_robot-0.82.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
28
- robotcode_robot-0.82.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
29
- robotcode_robot-0.82.0.dist-info/RECORD,,
26
+ robotcode_robot-0.82.2.dist-info/METADATA,sha256=pRwfD5QyBb_O5ISAAeBTS_ERjDt3ksXL7ac5FqxT2cg,2240
27
+ robotcode_robot-0.82.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
28
+ robotcode_robot-0.82.2.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
29
+ robotcode_robot-0.82.2.dist-info/RECORD,,