robotcode-robot 0.95.0__py3-none-any.whl → 0.95.2__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- robotcode/robot/__version__.py +1 -1
- robotcode/robot/diagnostics/entities.py +8 -8
- robotcode/robot/diagnostics/imports_manager.py +3 -10
- robotcode/robot/diagnostics/keyword_finder.py +40 -39
- robotcode/robot/diagnostics/library_doc.py +197 -204
- robotcode/robot/diagnostics/model_helper.py +3 -3
- robotcode/robot/diagnostics/namespace.py +2 -7
- robotcode/robot/diagnostics/namespace_analyzer.py +8 -5
- robotcode/robot/utils/ast.py +42 -60
- robotcode/robot/utils/markdownformatter.py +11 -11
- robotcode/robot/utils/match.py +6 -5
- robotcode/robot/utils/robot_path.py +2 -2
- robotcode/robot/utils/stubs.py +1 -25
- robotcode/robot/utils/variables.py +5 -5
- robotcode/robot/utils/visitor.py +2 -28
- {robotcode_robot-0.95.0.dist-info → robotcode_robot-0.95.2.dist-info}/METADATA +2 -2
- robotcode_robot-0.95.2.dist-info/RECORD +32 -0
- robotcode_robot-0.95.0.dist-info/RECORD +0 -32
- {robotcode_robot-0.95.0.dist-info → robotcode_robot-0.95.2.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.95.0.dist-info → robotcode_robot-0.95.2.dist-info}/licenses/LICENSE.txt +0 -0
@@ -44,7 +44,7 @@ from robot.output.logger import LOGGER
|
|
44
44
|
from robot.output.loggerhelper import AbstractLogger
|
45
45
|
from robot.parsing.lexer.tokens import Token
|
46
46
|
from robot.parsing.lexer.tokens import Token as RobotToken
|
47
|
-
from robot.parsing.model.blocks import Keyword
|
47
|
+
from robot.parsing.model.blocks import Keyword, KeywordSection, Section, SettingSection
|
48
48
|
from robot.parsing.model.statements import Arguments, KeywordName
|
49
49
|
from robot.running.arguments.argumentresolver import ArgumentResolver, DictToKwargs, NamedArgumentResolver
|
50
50
|
from robot.running.arguments.argumentresolver import VariableReplacer as ArgumentsVariableReplacer
|
@@ -64,7 +64,18 @@ from robot.variables.finders import VariableFinder
|
|
64
64
|
from robot.variables.replacer import VariableReplacer
|
65
65
|
from robotcode.core.lsp.types import Position, Range
|
66
66
|
from robotcode.core.utils.path import normalized_path
|
67
|
-
|
67
|
+
|
68
|
+
from ..utils import get_robot_version
|
69
|
+
from ..utils.ast import (
|
70
|
+
cached_isinstance,
|
71
|
+
get_variable_token,
|
72
|
+
range_from_token,
|
73
|
+
strip_variable_token,
|
74
|
+
)
|
75
|
+
from ..utils.markdownformatter import MarkDownFormatter
|
76
|
+
from ..utils.match import normalize, normalize_namespace
|
77
|
+
from ..utils.variables import contains_variable
|
78
|
+
from .entities import (
|
68
79
|
ArgumentDefinition,
|
69
80
|
ImportedVariableDefinition,
|
70
81
|
LibraryArgumentDefinition,
|
@@ -72,18 +83,6 @@ from robotcode.robot.diagnostics.entities import (
|
|
72
83
|
SourceEntity,
|
73
84
|
single_call,
|
74
85
|
)
|
75
|
-
from robotcode.robot.utils import get_robot_version
|
76
|
-
from robotcode.robot.utils.ast import (
|
77
|
-
cached_isinstance,
|
78
|
-
get_variable_token,
|
79
|
-
range_from_token,
|
80
|
-
strip_variable_token,
|
81
|
-
)
|
82
|
-
from robotcode.robot.utils.markdownformatter import MarkDownFormatter
|
83
|
-
from robotcode.robot.utils.match import normalize, normalize_namespace
|
84
|
-
from robotcode.robot.utils.stubs import HasError, HasErrors
|
85
|
-
|
86
|
-
from ..utils.variables import contains_variable
|
87
86
|
|
88
87
|
if get_robot_version() < (7, 0):
|
89
88
|
from robot.running.handlers import _PythonHandler, _PythonInitHandler # pyright: ignore[reportMissingImports]
|
@@ -201,22 +200,36 @@ def convert_from_rest(text: str) -> str:
|
|
201
200
|
|
202
201
|
if get_robot_version() >= (6, 0):
|
203
202
|
|
204
|
-
|
203
|
+
# monkey patch robot framework
|
204
|
+
_old_from_name = EmbeddedArguments.from_name
|
205
|
+
|
206
|
+
@functools.lru_cache(maxsize=8192)
|
207
|
+
def _new_from_name(name: str) -> EmbeddedArguments:
|
208
|
+
return _old_from_name(name)
|
209
|
+
|
210
|
+
EmbeddedArguments.from_name = _new_from_name
|
211
|
+
|
205
212
|
def _get_embedded_arguments(name: str) -> Any:
|
206
213
|
try:
|
207
214
|
return EmbeddedArguments.from_name(name)
|
208
215
|
except (VariableError, DataError):
|
209
216
|
return ()
|
210
217
|
|
218
|
+
def _match_embedded(embedded_arguments: EmbeddedArguments, name: str) -> bool:
|
219
|
+
return embedded_arguments.match(name) is not None
|
220
|
+
|
211
221
|
else:
|
212
222
|
|
213
|
-
@functools.lru_cache(maxsize=
|
223
|
+
@functools.lru_cache(maxsize=8192)
|
214
224
|
def _get_embedded_arguments(name: str) -> Any:
|
215
225
|
try:
|
216
226
|
return EmbeddedArguments(name)
|
217
227
|
except (VariableError, DataError):
|
218
228
|
return ()
|
219
229
|
|
230
|
+
def _match_embedded(embedded_arguments: EmbeddedArguments, name: str) -> bool:
|
231
|
+
return embedded_arguments.name.match(name) is not None
|
232
|
+
|
220
233
|
|
221
234
|
def is_embedded_keyword(name: str) -> bool:
|
222
235
|
try:
|
@@ -239,59 +252,50 @@ class KeywordMatcher:
|
|
239
252
|
self._can_have_embedded = can_have_embedded and not is_namespace
|
240
253
|
self._is_namespace = is_namespace
|
241
254
|
self._normalized_name: Optional[str] = None
|
242
|
-
|
255
|
+
|
256
|
+
self.embedded_arguments: Optional[EmbeddedArguments] = (
|
257
|
+
_get_embedded_arguments(self.name) or None if self._can_have_embedded else None
|
258
|
+
)
|
243
259
|
|
244
260
|
@property
|
245
261
|
def normalized_name(self) -> str:
|
246
262
|
if self._normalized_name is None:
|
247
|
-
self._normalized_name =
|
263
|
+
self._normalized_name = normalize_namespace(self.name) if self._is_namespace else normalize(self.name)
|
248
264
|
|
249
265
|
return self._normalized_name
|
250
266
|
|
251
|
-
@property
|
252
|
-
def embedded_arguments(self) -> Any:
|
253
|
-
if self._embedded_arguments is None:
|
254
|
-
if self._can_have_embedded:
|
255
|
-
self._embedded_arguments = _get_embedded_arguments(self.name)
|
256
|
-
else:
|
257
|
-
self._embedded_arguments = ()
|
258
|
-
|
259
|
-
return self._embedded_arguments
|
260
|
-
|
261
|
-
if get_robot_version() >= (6, 0):
|
262
|
-
|
263
|
-
def __match_embedded(self, name: str) -> bool:
|
264
|
-
return self.embedded_arguments.match(name) is not None
|
265
|
-
|
266
|
-
else:
|
267
|
-
|
268
|
-
def __match_embedded(self, name: str) -> bool:
|
269
|
-
return self.embedded_arguments.name.match(name) is not None
|
270
|
-
|
271
267
|
def __eq__(self, o: object) -> bool:
|
272
|
-
if
|
268
|
+
if type(o) is KeywordMatcher:
|
273
269
|
if self._is_namespace != o._is_namespace:
|
274
270
|
return False
|
275
271
|
|
276
|
-
if
|
272
|
+
if self.embedded_arguments is not None:
|
277
273
|
return self.normalized_name == o.normalized_name
|
278
274
|
|
279
275
|
o = o.name
|
280
276
|
|
281
|
-
if
|
277
|
+
if type(o) is not str:
|
282
278
|
return False
|
283
279
|
|
284
|
-
|
285
|
-
return self.__match_embedded(o)
|
280
|
+
return self.match_string(o)
|
286
281
|
|
287
|
-
|
282
|
+
def match_string(self, o: str) -> bool:
|
283
|
+
if self.embedded_arguments is not None:
|
284
|
+
return _match_embedded(self.embedded_arguments, o)
|
285
|
+
|
286
|
+
return self.normalized_name == (normalize_namespace(o) if self._is_namespace else normalize(o))
|
288
287
|
|
289
288
|
@single_call
|
290
289
|
def __hash__(self) -> int:
|
291
290
|
return hash(
|
292
|
-
(
|
293
|
-
|
294
|
-
|
291
|
+
(
|
292
|
+
self.normalized_name,
|
293
|
+
self._is_namespace,
|
294
|
+
self._can_have_embedded,
|
295
|
+
self.embedded_arguments,
|
296
|
+
self.embedded_arguments.name if self.embedded_arguments else None,
|
297
|
+
self.embedded_arguments.args if self.embedded_arguments else None,
|
298
|
+
)
|
295
299
|
)
|
296
300
|
|
297
301
|
def __str__(self) -> str:
|
@@ -618,7 +622,6 @@ class KeywordDoc(SourceEntity):
|
|
618
622
|
libname: Optional[str] = None
|
619
623
|
libtype: Optional[str] = None
|
620
624
|
longname: Optional[str] = None
|
621
|
-
is_embedded: bool = False
|
622
625
|
errors: Optional[List[Error]] = field(default=None, compare=False)
|
623
626
|
doc_format: str = ROBOT_DOC_FORMAT
|
624
627
|
is_error_handler: bool = False
|
@@ -667,13 +670,15 @@ class KeywordDoc(SourceEntity):
|
|
667
670
|
def __str__(self) -> str:
|
668
671
|
return f"{self.name}({', '.join(str(arg) for arg in self.arguments)})"
|
669
672
|
|
670
|
-
@
|
673
|
+
@functools.cached_property
|
674
|
+
def is_embedded(self) -> bool:
|
675
|
+
return self.matcher.embedded_arguments is not None
|
676
|
+
|
677
|
+
@functools.cached_property
|
671
678
|
def matcher(self) -> KeywordMatcher:
|
672
|
-
|
673
|
-
self.__matcher = KeywordMatcher(self.name)
|
674
|
-
return self.__matcher
|
679
|
+
return KeywordMatcher(self.name)
|
675
680
|
|
676
|
-
@
|
681
|
+
@functools.cached_property
|
677
682
|
def is_deprecated(self) -> bool:
|
678
683
|
return self.deprecated or DEPRECATED_PATTERN.match(self.doc) is not None
|
679
684
|
|
@@ -685,31 +690,31 @@ class KeywordDoc(SourceEntity):
|
|
685
690
|
def is_library_keyword(self) -> bool:
|
686
691
|
return self.libtype == "LIBRARY"
|
687
692
|
|
688
|
-
@
|
693
|
+
@functools.cached_property
|
689
694
|
def deprecated_message(self) -> str:
|
690
695
|
if (m := DEPRECATED_PATTERN.match(self.doc)) is not None:
|
691
696
|
return m.group("message").strip()
|
692
697
|
return ""
|
693
698
|
|
694
|
-
@
|
699
|
+
@functools.cached_property
|
695
700
|
def name_range(self) -> Range:
|
696
701
|
if self.name_token is not None:
|
697
702
|
return range_from_token(self.name_token)
|
698
703
|
|
699
704
|
return Range.invalid()
|
700
705
|
|
701
|
-
@
|
706
|
+
@functools.cached_property
|
702
707
|
def normalized_tags(self) -> List[str]:
|
703
708
|
return [normalize(tag) for tag in self.tags]
|
704
709
|
|
705
|
-
@
|
710
|
+
@functools.cached_property
|
706
711
|
def is_private(self) -> bool:
|
707
712
|
if get_robot_version() < (6, 0):
|
708
713
|
return False
|
709
714
|
|
710
|
-
return "robot:private" in self.normalized_tags
|
715
|
+
return "robot:private" in self.normalized_tags
|
711
716
|
|
712
|
-
@
|
717
|
+
@functools.cached_property
|
713
718
|
def range(self) -> Range:
|
714
719
|
if self.name_token is not None:
|
715
720
|
return range_from_token(self.name_token)
|
@@ -820,7 +825,7 @@ class KeywordDoc(SourceEntity):
|
|
820
825
|
|
821
826
|
return result
|
822
827
|
|
823
|
-
@
|
828
|
+
@functools.cached_property
|
824
829
|
def signature(self) -> str:
|
825
830
|
return (
|
826
831
|
f'({self.type}) "{self.name}": ('
|
@@ -893,7 +898,6 @@ class KeywordDoc(SourceEntity):
|
|
893
898
|
self.type,
|
894
899
|
self.libname,
|
895
900
|
self.libtype,
|
896
|
-
self.is_embedded,
|
897
901
|
self.is_initializer,
|
898
902
|
self.is_error_handler,
|
899
903
|
self.doc_format,
|
@@ -919,19 +923,13 @@ class KeywordStore:
|
|
919
923
|
source_type: Optional[str] = None
|
920
924
|
keywords: List[KeywordDoc] = field(default_factory=list)
|
921
925
|
|
922
|
-
@property
|
923
|
-
def _matchers(self) -> Dict[KeywordMatcher, KeywordDoc]:
|
924
|
-
if not hasattr(self, "__matchers"):
|
925
|
-
self.__matchers = {v.matcher: v for v in self.keywords}
|
926
|
-
return self.__matchers
|
927
|
-
|
928
926
|
def __getitem__(self, key: str) -> KeywordDoc:
|
929
|
-
items = [
|
927
|
+
items = [v for v in self.keywords if v.matcher == key]
|
930
928
|
|
931
929
|
if not items:
|
932
930
|
raise KeyError
|
933
931
|
if len(items) == 1:
|
934
|
-
return items[0]
|
932
|
+
return items[0]
|
935
933
|
|
936
934
|
if self.source and self.source_type:
|
937
935
|
file_info = ""
|
@@ -946,14 +944,14 @@ class KeywordStore:
|
|
946
944
|
else:
|
947
945
|
file_info = "File"
|
948
946
|
error = [f"{file_info} contains multiple keywords matching name '{key}':"]
|
949
|
-
names = sorted(
|
947
|
+
names = sorted(v.name for v in items)
|
950
948
|
raise KeywordError(
|
951
949
|
"\n ".join(error + names),
|
952
|
-
multiple_keywords=[v for
|
950
|
+
multiple_keywords=[v for v in items],
|
953
951
|
)
|
954
952
|
|
955
953
|
def __contains__(self, _x: object) -> bool:
|
956
|
-
return any(
|
954
|
+
return any(v.matcher == _x for v in self.keywords)
|
957
955
|
|
958
956
|
def __len__(self) -> int:
|
959
957
|
return len(self.keywords)
|
@@ -983,7 +981,7 @@ class KeywordStore:
|
|
983
981
|
return list(self.iter_all(key))
|
984
982
|
|
985
983
|
def iter_all(self, key: str) -> Iterable[KeywordDoc]:
|
986
|
-
|
984
|
+
return (v for v in self.keywords if v.matcher.match_string(key))
|
987
985
|
|
988
986
|
|
989
987
|
@dataclass
|
@@ -1296,12 +1294,12 @@ class VariablesDoc(LibraryDoc):
|
|
1296
1294
|
return result
|
1297
1295
|
|
1298
1296
|
|
1299
|
-
@functools.lru_cache(maxsize=
|
1297
|
+
@functools.lru_cache(maxsize=8192)
|
1300
1298
|
def is_library_by_path(path: str) -> bool:
|
1301
1299
|
return path.lower().endswith((".py", "/", os.sep))
|
1302
1300
|
|
1303
1301
|
|
1304
|
-
@functools.lru_cache(maxsize=
|
1302
|
+
@functools.lru_cache(maxsize=8192)
|
1305
1303
|
def is_variables_by_path(path: str) -> bool:
|
1306
1304
|
if get_robot_version() >= (6, 1):
|
1307
1305
|
return path.lower().endswith((".py", ".yml", ".yaml", ".json", "/", os.sep))
|
@@ -2030,7 +2028,6 @@ def get_library_doc(
|
|
2030
2028
|
libname=libdoc.name,
|
2031
2029
|
libtype=libdoc.type,
|
2032
2030
|
longname=f"{libdoc.name}.{kw[0].name}",
|
2033
|
-
is_embedded=is_embedded_keyword(kw[0].name),
|
2034
2031
|
doc_format=str(lib.doc_format) or ROBOT_DOC_FORMAT,
|
2035
2032
|
is_error_handler=kw[1].is_error_handler,
|
2036
2033
|
error_handler_message=kw[1].error_handler_message,
|
@@ -2710,133 +2707,146 @@ def complete_variables_import(
|
|
2710
2707
|
return list(set(result))
|
2711
2708
|
|
2712
2709
|
|
2713
|
-
|
2714
|
-
model: ast.AST,
|
2715
|
-
source: str,
|
2716
|
-
append_model_errors: bool = True,
|
2717
|
-
) -> LibraryDoc:
|
2718
|
-
errors: List[Error] = []
|
2719
|
-
keyword_name_nodes: List[KeywordName] = []
|
2720
|
-
keywords_nodes: List[Keyword] = []
|
2721
|
-
for node in ast.walk(model):
|
2722
|
-
if isinstance(node, Keyword):
|
2723
|
-
keywords_nodes.append(node)
|
2724
|
-
if isinstance(node, KeywordName):
|
2725
|
-
keyword_name_nodes.append(node)
|
2726
|
-
|
2727
|
-
error = node.error if isinstance(node, HasError) else None
|
2728
|
-
if error is not None:
|
2729
|
-
errors.append(
|
2730
|
-
Error(
|
2731
|
-
message=error,
|
2732
|
-
type_name="ModelError",
|
2733
|
-
source=source,
|
2734
|
-
line_no=node.lineno, # type: ignore
|
2735
|
-
)
|
2736
|
-
)
|
2737
|
-
if append_model_errors:
|
2738
|
-
node_errors = node.errors if isinstance(node, HasErrors) else None
|
2739
|
-
if node_errors is not None:
|
2740
|
-
for e in node_errors:
|
2741
|
-
errors.append(
|
2742
|
-
Error(
|
2743
|
-
message=e,
|
2744
|
-
type_name="ModelError",
|
2745
|
-
source=source,
|
2746
|
-
line_no=node.lineno, # type: ignore
|
2747
|
-
)
|
2748
|
-
)
|
2710
|
+
if get_robot_version() < (7, 0):
|
2749
2711
|
|
2750
|
-
|
2751
|
-
|
2752
|
-
if keyword_name.lineno == line:
|
2753
|
-
return cast(Token, keyword_name.get_token(RobotToken.KEYWORD_NAME))
|
2712
|
+
class _MyUserLibrary(UserLibrary):
|
2713
|
+
current_kw: Any = None
|
2754
2714
|
|
2755
|
-
|
2715
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
2716
|
+
self.errors: List[Error] = []
|
2717
|
+
super().__init__(*args, **kwargs)
|
2756
2718
|
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2719
|
+
def _log_creating_failed(self, handler: UserErrorHandler, error: BaseException) -> None:
|
2720
|
+
err = Error(
|
2721
|
+
message=f"Creating keyword '{handler.name}' failed: {error!s}",
|
2722
|
+
type_name=type(error).__qualname__,
|
2723
|
+
source=self.current_kw.source if self.current_kw is not None else None,
|
2724
|
+
line_no=self.current_kw.lineno if self.current_kw is not None else None,
|
2725
|
+
)
|
2726
|
+
self.errors.append(err)
|
2763
2727
|
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2728
|
+
def _create_handler(self, kw: Any) -> Any:
|
2729
|
+
self.current_kw = kw
|
2730
|
+
try:
|
2731
|
+
handler = super()._create_handler(kw)
|
2732
|
+
handler.errors = None
|
2733
|
+
except DataError as e:
|
2734
|
+
err = Error(
|
2735
|
+
message=str(e),
|
2736
|
+
type_name=type(e).__qualname__,
|
2737
|
+
source=kw.source,
|
2738
|
+
line_no=kw.lineno,
|
2739
|
+
)
|
2740
|
+
self.errors.append(err)
|
2770
2741
|
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2742
|
+
handler = UserErrorHandler(e, kw.name, self.name)
|
2743
|
+
handler.source = kw.source
|
2744
|
+
handler.lineno = kw.lineno
|
2774
2745
|
|
2775
|
-
|
2776
|
-
try:
|
2777
|
-
argument = get_variable_token(argument_token)
|
2778
|
-
|
2779
|
-
if argument is not None and argument.value != "@{}":
|
2780
|
-
if argument.value not in args:
|
2781
|
-
args.append(argument.value)
|
2782
|
-
arg_def = ArgumentDefinition(
|
2783
|
-
name=argument.value,
|
2784
|
-
name_token=strip_variable_token(argument),
|
2785
|
-
line_no=argument.lineno,
|
2786
|
-
col_offset=argument.col_offset,
|
2787
|
-
end_line_no=argument.lineno,
|
2788
|
-
end_col_offset=argument.end_col_offset,
|
2789
|
-
source=source,
|
2790
|
-
)
|
2791
|
-
argument_definitions.append(arg_def)
|
2746
|
+
handler.errors = [err]
|
2792
2747
|
|
2793
|
-
|
2794
|
-
pass
|
2748
|
+
return handler
|
2795
2749
|
|
2796
|
-
return argument_definitions
|
2797
2750
|
|
2798
|
-
|
2751
|
+
def _get_keyword_name_token_from_line(keyword_name_nodes: Dict[int, KeywordName], line: int) -> Optional[Token]:
|
2752
|
+
keyword_name = keyword_name_nodes.get(line, None)
|
2753
|
+
if keyword_name is None:
|
2754
|
+
return None
|
2755
|
+
return cast(Token, keyword_name.get_token(RobotToken.KEYWORD_NAME))
|
2799
2756
|
|
2800
|
-
with LOGGER.cache_only:
|
2801
|
-
ResourceBuilder(res).visit(model)
|
2802
2757
|
|
2803
|
-
|
2758
|
+
def _get_argument_definitions_from_line(
|
2759
|
+
keywords_nodes: Dict[int, Keyword],
|
2760
|
+
source: Optional[str],
|
2761
|
+
line: int,
|
2762
|
+
) -> List[ArgumentDefinition]:
|
2763
|
+
keyword_node = keywords_nodes.get(line, None)
|
2764
|
+
if keyword_node is None:
|
2765
|
+
return []
|
2804
2766
|
|
2805
|
-
|
2806
|
-
|
2767
|
+
arguments_node = next(
|
2768
|
+
(n for n in ast.walk(keyword_node) if isinstance(n, Arguments)),
|
2769
|
+
None,
|
2770
|
+
)
|
2771
|
+
if arguments_node is None:
|
2772
|
+
return []
|
2807
2773
|
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
type_name=type(error).__qualname__,
|
2812
|
-
source=self.current_kw.source if self.current_kw is not None else None,
|
2813
|
-
line_no=self.current_kw.lineno if self.current_kw is not None else None,
|
2814
|
-
)
|
2815
|
-
errors.append(err)
|
2774
|
+
args: List[str] = []
|
2775
|
+
arguments = arguments_node.get_tokens(RobotToken.ARGUMENT)
|
2776
|
+
argument_definitions = []
|
2816
2777
|
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2820
|
-
|
2821
|
-
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
line_no=
|
2778
|
+
for argument_token in (cast(RobotToken, e) for e in arguments):
|
2779
|
+
try:
|
2780
|
+
argument = get_variable_token(argument_token)
|
2781
|
+
|
2782
|
+
if argument is not None and argument.value != "@{}":
|
2783
|
+
if argument.value not in args:
|
2784
|
+
args.append(argument.value)
|
2785
|
+
arg_def = ArgumentDefinition(
|
2786
|
+
name=argument.value,
|
2787
|
+
name_token=strip_variable_token(argument),
|
2788
|
+
line_no=argument.lineno,
|
2789
|
+
col_offset=argument.col_offset,
|
2790
|
+
end_line_no=argument.lineno,
|
2791
|
+
end_col_offset=argument.end_col_offset,
|
2792
|
+
source=source,
|
2828
2793
|
)
|
2829
|
-
|
2794
|
+
argument_definitions.append(arg_def)
|
2830
2795
|
|
2831
|
-
|
2832
|
-
|
2833
|
-
handler.lineno = kw.lineno
|
2796
|
+
except VariableError:
|
2797
|
+
pass
|
2834
2798
|
|
2835
|
-
|
2799
|
+
return argument_definitions
|
2800
|
+
|
2801
|
+
|
2802
|
+
class _MyResourceBuilder(ResourceBuilder):
|
2803
|
+
def __init__(self, resource: Any) -> None:
|
2804
|
+
super().__init__(resource)
|
2805
|
+
self.keyword_name_nodes: Dict[int, KeywordName] = {}
|
2806
|
+
self.keywords_nodes: Dict[int, Keyword] = {}
|
2807
|
+
|
2808
|
+
def visit_Section(self, node: Section) -> None: # noqa: N802
|
2809
|
+
if isinstance(node, (SettingSection, KeywordSection)):
|
2810
|
+
self.generic_visit(node)
|
2811
|
+
|
2812
|
+
def visit_Keyword(self, node: Keyword) -> None: # noqa: N802
|
2813
|
+
self.keywords_nodes[node.lineno] = node
|
2814
|
+
super().visit_Keyword(node)
|
2815
|
+
if node.header is not None:
|
2816
|
+
self.keyword_name_nodes[node.lineno] = node.header
|
2817
|
+
|
2818
|
+
|
2819
|
+
def _get_kw_errors(kw: Any) -> Any:
|
2820
|
+
r = kw.errors if hasattr(kw, "errors") else None
|
2821
|
+
if get_robot_version() >= (7, 0) and kw.error:
|
2822
|
+
if not r:
|
2823
|
+
r = []
|
2824
|
+
r.append(
|
2825
|
+
Error(
|
2826
|
+
message=str(kw.error),
|
2827
|
+
type_name="KeywordError",
|
2828
|
+
source=kw.source,
|
2829
|
+
line_no=kw.lineno,
|
2830
|
+
)
|
2831
|
+
)
|
2832
|
+
return r
|
2836
2833
|
|
2837
|
-
return handler
|
2838
2834
|
|
2839
|
-
|
2835
|
+
def get_model_doc(
|
2836
|
+
model: ast.AST,
|
2837
|
+
source: str,
|
2838
|
+
) -> LibraryDoc:
|
2839
|
+
res = ResourceFile(source=source)
|
2840
|
+
|
2841
|
+
res_builder = _MyResourceBuilder(res)
|
2842
|
+
with LOGGER.cache_only:
|
2843
|
+
res_builder.visit(model)
|
2844
|
+
|
2845
|
+
keyword_name_nodes: Dict[int, KeywordName] = res_builder.keyword_name_nodes
|
2846
|
+
keywords_nodes: Dict[int, Keyword] = res_builder.keywords_nodes
|
2847
|
+
|
2848
|
+
if get_robot_version() < (7, 0):
|
2849
|
+
lib = _MyUserLibrary(res)
|
2840
2850
|
else:
|
2841
2851
|
lib = res
|
2842
2852
|
|
@@ -2847,24 +2857,8 @@ def get_model_doc(
|
|
2847
2857
|
scope="GLOBAL",
|
2848
2858
|
source=source,
|
2849
2859
|
line_no=1,
|
2850
|
-
errors=errors,
|
2851
2860
|
)
|
2852
2861
|
|
2853
|
-
def get_kw_errors(kw: Any) -> Any:
|
2854
|
-
r = kw.errors if hasattr(kw, "errors") else None
|
2855
|
-
if get_robot_version() >= (7, 0) and kw.error:
|
2856
|
-
if not r:
|
2857
|
-
r = []
|
2858
|
-
r.append(
|
2859
|
-
Error(
|
2860
|
-
message=str(kw.error),
|
2861
|
-
type_name="KeywordError",
|
2862
|
-
source=kw.source,
|
2863
|
-
line_no=kw.lineno,
|
2864
|
-
)
|
2865
|
-
)
|
2866
|
-
return r
|
2867
|
-
|
2868
2862
|
libdoc.keywords = KeywordStore(
|
2869
2863
|
source=libdoc.name,
|
2870
2864
|
source_type=libdoc.type,
|
@@ -2875,7 +2869,7 @@ def get_model_doc(
|
|
2875
2869
|
doc=kw[0].doc,
|
2876
2870
|
tags=list(kw[0].tags),
|
2877
2871
|
source=str(kw[0].source),
|
2878
|
-
name_token=
|
2872
|
+
name_token=_get_keyword_name_token_from_line(keyword_name_nodes, kw[0].lineno),
|
2879
2873
|
line_no=kw[0].lineno if kw[0].lineno is not None else -1,
|
2880
2874
|
col_offset=-1,
|
2881
2875
|
end_col_offset=-1,
|
@@ -2883,8 +2877,7 @@ def get_model_doc(
|
|
2883
2877
|
libname=libdoc.name,
|
2884
2878
|
libtype=libdoc.type,
|
2885
2879
|
longname=f"{libdoc.name}.{kw[0].name}",
|
2886
|
-
|
2887
|
-
errors=get_kw_errors(kw[1]),
|
2880
|
+
errors=_get_kw_errors(kw[1]),
|
2888
2881
|
is_error_handler=isinstance(kw[1], UserErrorHandler),
|
2889
2882
|
error_handler_message=(
|
2890
2883
|
str(cast(UserErrorHandler, kw[1]).error) if isinstance(kw[1], UserErrorHandler) else None
|
@@ -2892,7 +2885,7 @@ def get_model_doc(
|
|
2892
2885
|
arguments_spec=ArgumentSpec.from_robot_argument_spec(
|
2893
2886
|
kw[1].arguments if get_robot_version() < (7, 0) else kw[1].args
|
2894
2887
|
),
|
2895
|
-
argument_definitions=
|
2888
|
+
argument_definitions=_get_argument_definitions_from_line(keywords_nodes, source, kw[0].lineno),
|
2896
2889
|
)
|
2897
2890
|
for kw in [
|
2898
2891
|
(KeywordDocBuilder(resource=True).build_keyword(lw), lw)
|
@@ -665,12 +665,12 @@ class ModelHelper:
|
|
665
665
|
|
666
666
|
@classmethod
|
667
667
|
def get_keyword_definition_at_token(cls, library_doc: LibraryDoc, token: Token) -> Optional[KeywordDoc]:
|
668
|
-
return cls.get_keyword_definition_at_line(library_doc, token.
|
668
|
+
return cls.get_keyword_definition_at_line(library_doc, token.lineno)
|
669
669
|
|
670
670
|
@classmethod
|
671
|
-
def get_keyword_definition_at_line(cls, library_doc: LibraryDoc,
|
671
|
+
def get_keyword_definition_at_line(cls, library_doc: LibraryDoc, line: int) -> Optional[KeywordDoc]:
|
672
672
|
return next(
|
673
|
-
(k for k in library_doc.keywords.
|
673
|
+
(k for k in library_doc.keywords.keywords if k.line_no == line),
|
674
674
|
None,
|
675
675
|
)
|
676
676
|
|
@@ -910,11 +910,7 @@ class Namespace:
|
|
910
910
|
def get_library_doc(self) -> LibraryDoc:
|
911
911
|
with self._library_doc_lock:
|
912
912
|
if self._library_doc is None:
|
913
|
-
self._library_doc = self.imports_manager.get_libdoc_from_model(
|
914
|
-
self.model,
|
915
|
-
self.source,
|
916
|
-
append_model_errors=self.document_type is not None and self.document_type == DocumentType.RESOURCE,
|
917
|
-
)
|
913
|
+
self._library_doc = self.imports_manager.get_libdoc_from_model(self.model, self.source)
|
918
914
|
|
919
915
|
return self._library_doc
|
920
916
|
|
@@ -1887,7 +1883,6 @@ class Namespace:
|
|
1887
1883
|
source=DIAGNOSTICS_SOURCE_NAME,
|
1888
1884
|
code=err.type_name,
|
1889
1885
|
)
|
1890
|
-
# TODO: implement CancelationToken
|
1891
1886
|
except CancelledError:
|
1892
1887
|
canceled = True
|
1893
1888
|
self._logger.debug("analyzing canceled")
|
@@ -1904,7 +1899,7 @@ class Namespace:
|
|
1904
1899
|
|
1905
1900
|
def create_finder(self) -> "KeywordFinder":
|
1906
1901
|
self.ensure_initialized()
|
1907
|
-
return KeywordFinder(self
|
1902
|
+
return KeywordFinder(self)
|
1908
1903
|
|
1909
1904
|
@_logger.call(condition=lambda self, name, **kwargs: self._finder is not None and name not in self._finder._cache)
|
1910
1905
|
def find_keyword(
|