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 @@ def visit_Variable(self, node: Statement) -> None: # noqa: N802
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 @@ def __init__(
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 @@ def visit(self, node: ast.AST) -> None:
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 @@ def visit_KeywordName(self, node: Statement) -> None: # noqa: N802
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 @@ def yield_variables(
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 @@ def yield_variables(
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 @@ def find_variable(
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 @@ def find_variable(
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
0 commit comments