robotcode-robot 0.94.0__py3-none-any.whl → 0.95.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ast
4
+ import functools
4
5
  import hashlib
5
6
  import importlib
6
7
  import importlib.util
@@ -61,7 +62,6 @@ from robot.variables import Variables
61
62
  from robot.variables.filesetter import PythonImporter, YamlImporter
62
63
  from robot.variables.finders import VariableFinder
63
64
  from robot.variables.replacer import VariableReplacer
64
- from robot.variables.search import contains_variable
65
65
  from robotcode.core.lsp.types import Position, Range
66
66
  from robotcode.core.utils.path import normalized_path
67
67
  from robotcode.robot.diagnostics.entities import (
@@ -76,12 +76,14 @@ from robotcode.robot.utils import get_robot_version
76
76
  from robotcode.robot.utils.ast import (
77
77
  cached_isinstance,
78
78
  get_variable_token,
79
+ iter_nodes,
79
80
  range_from_token,
80
81
  strip_variable_token,
81
82
  )
82
83
  from robotcode.robot.utils.markdownformatter import MarkDownFormatter
83
84
  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
85
87
 
86
88
  if get_robot_version() < (7, 0):
87
89
  from robot.running.handlers import _PythonHandler, _PythonInitHandler # pyright: ignore[reportMissingImports]
@@ -197,14 +199,29 @@ def convert_from_rest(text: str) -> str:
197
199
  return text
198
200
 
199
201
 
202
+ if get_robot_version() >= (6, 0):
203
+
204
+ @functools.lru_cache(maxsize=None)
205
+ def _get_embedded_arguments(name: str) -> Any:
206
+ try:
207
+ return EmbeddedArguments.from_name(name)
208
+ except (VariableError, DataError):
209
+ return ()
210
+
211
+ else:
212
+
213
+ @functools.lru_cache(maxsize=None)
214
+ def _get_embedded_arguments(name: str) -> Any:
215
+ try:
216
+ return EmbeddedArguments(name)
217
+ except (VariableError, DataError):
218
+ return ()
219
+
220
+
200
221
  def is_embedded_keyword(name: str) -> bool:
201
222
  try:
202
- if get_robot_version() >= (6, 0):
203
- if EmbeddedArguments.from_name(name):
204
- return True
205
- else:
206
- if EmbeddedArguments(name):
207
- return True
223
+ if _get_embedded_arguments(name):
224
+ return True
208
225
  except (VariableError, DataError):
209
226
  return True
210
227
 
@@ -222,7 +239,11 @@ class KeywordMatcher:
222
239
  self._can_have_embedded = can_have_embedded and not is_namespace
223
240
  self._is_namespace = is_namespace
224
241
  self._normalized_name: Optional[str] = None
225
- self._embedded_arguments: Any = None
242
+
243
+ self.embedded_arguments: Optional[EmbeddedArguments] = (
244
+ _get_embedded_arguments(self.name) or None if self._can_have_embedded else None
245
+ )
246
+ self._match_cache: Dict[str, bool] = {}
226
247
 
227
248
  @property
228
249
  def normalized_name(self) -> str:
@@ -231,24 +252,18 @@ class KeywordMatcher:
231
252
 
232
253
  return self._normalized_name
233
254
 
234
- @property
235
- def embedded_arguments(self) -> Any:
236
- if self._embedded_arguments is None:
237
- if self._can_have_embedded:
238
- try:
239
- if get_robot_version() >= (6, 0):
240
- self._embedded_arguments = EmbeddedArguments.from_name(self.name)
241
- else:
242
- self._embedded_arguments = EmbeddedArguments(self.name)
243
- except (VariableError, DataError):
244
- self._embedded_arguments = ()
245
- else:
246
- self._embedded_arguments = ()
255
+ if get_robot_version() >= (6, 0):
256
+
257
+ def __match_embedded(self, name: str) -> bool:
258
+ return self.embedded_arguments is not None and self.embedded_arguments.match(name) is not None
247
259
 
248
- return self._embedded_arguments
260
+ else:
261
+
262
+ def __match_embedded(self, name: str) -> bool:
263
+ return self.embedded_arguments is not None and self.embedded_arguments.name.match(name) is not None
249
264
 
250
265
  def __eq__(self, o: object) -> bool:
251
- if cached_isinstance(o, KeywordMatcher):
266
+ if type(o) is KeywordMatcher:
252
267
  if self._is_namespace != o._is_namespace:
253
268
  return False
254
269
 
@@ -257,14 +272,11 @@ class KeywordMatcher:
257
272
 
258
273
  o = o.name
259
274
 
260
- if not cached_isinstance(o, str):
275
+ if type(o) is not str:
261
276
  return False
262
277
 
263
278
  if self.embedded_arguments:
264
- if get_robot_version() >= (6, 0):
265
- return self.embedded_arguments.match(o) is not None
266
-
267
- return self.embedded_arguments.name.match(o) is not None
279
+ return self.__match_embedded(o)
268
280
 
269
281
  return self.normalized_name == str(normalize_namespace(o) if self._is_namespace else normalize(o))
270
282
 
@@ -649,13 +661,11 @@ class KeywordDoc(SourceEntity):
649
661
  def __str__(self) -> str:
650
662
  return f"{self.name}({', '.join(str(arg) for arg in self.arguments)})"
651
663
 
652
- @property
664
+ @functools.cached_property
653
665
  def matcher(self) -> KeywordMatcher:
654
- if not hasattr(self, "__matcher"):
655
- self.__matcher = KeywordMatcher(self.name)
656
- return self.__matcher
666
+ return KeywordMatcher(self.name)
657
667
 
658
- @property
668
+ @functools.cached_property
659
669
  def is_deprecated(self) -> bool:
660
670
  return self.deprecated or DEPRECATED_PATTERN.match(self.doc) is not None
661
671
 
@@ -667,13 +677,13 @@ class KeywordDoc(SourceEntity):
667
677
  def is_library_keyword(self) -> bool:
668
678
  return self.libtype == "LIBRARY"
669
679
 
670
- @property
680
+ @functools.cached_property
671
681
  def deprecated_message(self) -> str:
672
682
  if (m := DEPRECATED_PATTERN.match(self.doc)) is not None:
673
683
  return m.group("message").strip()
674
684
  return ""
675
685
 
676
- @property
686
+ @functools.cached_property
677
687
  def name_range(self) -> Range:
678
688
  if self.name_token is not None:
679
689
  return range_from_token(self.name_token)
@@ -691,7 +701,7 @@ class KeywordDoc(SourceEntity):
691
701
 
692
702
  return "robot:private" in self.normalized_tags()
693
703
 
694
- @property
704
+ @functools.cached_property
695
705
  def range(self) -> Range:
696
706
  if self.name_token is not None:
697
707
  return range_from_token(self.name_token)
@@ -802,7 +812,7 @@ class KeywordDoc(SourceEntity):
802
812
 
803
813
  return result
804
814
 
805
- @property
815
+ @functools.cached_property
806
816
  def signature(self) -> str:
807
817
  return (
808
818
  f'({self.type}) "{self.name}": ('
@@ -901,20 +911,13 @@ class KeywordStore:
901
911
  source_type: Optional[str] = None
902
912
  keywords: List[KeywordDoc] = field(default_factory=list)
903
913
 
904
- @property
905
- def _matchers(self) -> Dict[KeywordMatcher, KeywordDoc]:
906
- if not hasattr(self, "__matchers"):
907
- self.__matchers = {v.matcher: v for v in self.keywords}
908
- return self.__matchers
909
-
910
914
  def __getitem__(self, key: str) -> KeywordDoc:
911
- key_matcher = KeywordMatcher(key)
912
- items = [(k, v) for k, v in self._matchers.items() if k == key_matcher]
915
+ items = [v for v in self.keywords if v.matcher == key]
913
916
 
914
917
  if not items:
915
918
  raise KeyError
916
919
  if len(items) == 1:
917
- return items[0][1]
920
+ return items[0]
918
921
 
919
922
  if self.source and self.source_type:
920
923
  file_info = ""
@@ -929,16 +932,14 @@ class KeywordStore:
929
932
  else:
930
933
  file_info = "File"
931
934
  error = [f"{file_info} contains multiple keywords matching name '{key}':"]
932
- names = sorted(k.name for k, v in items)
935
+ names = sorted(v.name for v in items)
933
936
  raise KeywordError(
934
937
  "\n ".join(error + names),
935
- multiple_keywords=[v for _, v in items],
938
+ multiple_keywords=[v for v in items],
936
939
  )
937
940
 
938
941
  def __contains__(self, _x: object) -> bool:
939
- if not isinstance(_x, KeywordMatcher):
940
- _x = KeywordMatcher(str(_x))
941
- return any(k == _x for k in self._matchers.keys())
942
+ return any(v.matcher == _x for v in self.keywords)
942
943
 
943
944
  def __len__(self) -> int:
944
945
  return len(self.keywords)
@@ -968,8 +969,7 @@ class KeywordStore:
968
969
  return list(self.iter_all(key))
969
970
 
970
971
  def iter_all(self, key: str) -> Iterable[KeywordDoc]:
971
- key_matcher = KeywordMatcher(key)
972
- yield from (v for k, v in self._matchers.items() if k == key_matcher)
972
+ yield from (v for v in self.keywords if v.matcher == key)
973
973
 
974
974
 
975
975
  @dataclass
@@ -1282,10 +1282,12 @@ class VariablesDoc(LibraryDoc):
1282
1282
  return result
1283
1283
 
1284
1284
 
1285
+ @functools.lru_cache(maxsize=256)
1285
1286
  def is_library_by_path(path: str) -> bool:
1286
1287
  return path.lower().endswith((".py", "/", os.sep))
1287
1288
 
1288
1289
 
1290
+ @functools.lru_cache(maxsize=256)
1289
1291
  def is_variables_by_path(path: str) -> bool:
1290
1292
  if get_robot_version() >= (6, 1):
1291
1293
  return path.lower().endswith((".py", ".yml", ".yaml", ".json", "/", os.sep))
@@ -1656,9 +1658,8 @@ def _find_library_internal(
1656
1658
 
1657
1659
  robot_variables = None
1658
1660
 
1659
- robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
1660
-
1661
1661
  if contains_variable(name, "$@&%"):
1662
+ robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
1662
1663
  try:
1663
1664
  name = robot_variables.replace_string(name, ignore_errors=False)
1664
1665
  except DataError as error:
@@ -1711,6 +1712,52 @@ def get_robot_library_html_doc_str(
1711
1712
  return output.getvalue()
1712
1713
 
1713
1714
 
1715
+ class _Logger(AbstractLogger):
1716
+ def __init__(self) -> None:
1717
+ super().__init__()
1718
+ self.messages: List[Tuple[str, str, bool]] = []
1719
+
1720
+ def write(self, message: str, level: str, html: bool = False) -> None:
1721
+ self.messages.append((message, level, html))
1722
+
1723
+
1724
+ def _import_test_library(name: str) -> Union[Any, Tuple[Any, str]]:
1725
+ with OutputCapturer(library_import=True):
1726
+ importer = Importer("test library", LOGGER)
1727
+ return importer.import_class_or_module(name, return_source=True)
1728
+
1729
+
1730
+ def _get_test_library(
1731
+ libcode: Any,
1732
+ source: str,
1733
+ name: str,
1734
+ args: Optional[Tuple[Any, ...]] = None,
1735
+ variables: Optional[Dict[str, Optional[Any]]] = None,
1736
+ create_handlers: bool = True,
1737
+ logger: Any = LOGGER,
1738
+ ) -> Any:
1739
+ if get_robot_version() < (7, 0):
1740
+ libclass = robot.running.testlibraries._get_lib_class(libcode)
1741
+ lib = libclass(libcode, name, args or [], source, logger, variables)
1742
+ if create_handlers:
1743
+ lib.create_handlers()
1744
+ else:
1745
+ lib = robot.running.testlibraries.TestLibrary.from_code(
1746
+ libcode,
1747
+ name,
1748
+ source=Path(source),
1749
+ args=args or [],
1750
+ variables=variables,
1751
+ create_keywords=create_handlers,
1752
+ logger=logger,
1753
+ )
1754
+
1755
+ return lib
1756
+
1757
+
1758
+ _T = TypeVar("_T")
1759
+
1760
+
1714
1761
  def get_library_doc(
1715
1762
  name: str,
1716
1763
  args: Optional[Tuple[Any, ...]] = None,
@@ -1719,45 +1766,6 @@ def get_library_doc(
1719
1766
  command_line_variables: Optional[Dict[str, Optional[Any]]] = None,
1720
1767
  variables: Optional[Dict[str, Optional[Any]]] = None,
1721
1768
  ) -> LibraryDoc:
1722
- class Logger(AbstractLogger):
1723
- def __init__(self) -> None:
1724
- super().__init__()
1725
- self.messages: List[Tuple[str, str, bool]] = []
1726
-
1727
- def write(self, message: str, level: str, html: bool = False) -> None:
1728
- self.messages.append((message, level, html))
1729
-
1730
- def import_test_library(name: str) -> Union[Any, Tuple[Any, str]]:
1731
- with OutputCapturer(library_import=True):
1732
- importer = Importer("test library", LOGGER)
1733
- return importer.import_class_or_module(name, return_source=True)
1734
-
1735
- def get_test_library(
1736
- libcode: Any,
1737
- source: str,
1738
- name: str,
1739
- args: Optional[Tuple[Any, ...]] = None,
1740
- variables: Optional[Dict[str, Optional[Any]]] = None,
1741
- create_handlers: bool = True,
1742
- logger: Any = LOGGER,
1743
- ) -> Any:
1744
- if get_robot_version() < (7, 0):
1745
- libclass = robot.running.testlibraries._get_lib_class(libcode)
1746
- lib = libclass(libcode, name, args or [], source, logger, variables)
1747
- if create_handlers:
1748
- lib.create_handlers()
1749
- else:
1750
- lib = robot.running.testlibraries.TestLibrary.from_code(
1751
- libcode,
1752
- name,
1753
- source=Path(source),
1754
- args=args or [],
1755
- variables=variables,
1756
- create_keywords=create_handlers,
1757
- logger=logger,
1758
- )
1759
-
1760
- return lib
1761
1769
 
1762
1770
  with _std_capture() as std_capturer:
1763
1771
  import_name, robot_variables = _find_library_internal(
@@ -1781,7 +1789,7 @@ def get_library_doc(
1781
1789
 
1782
1790
  source = None
1783
1791
  try:
1784
- libcode, source = import_test_library(import_name)
1792
+ libcode, source = _import_test_library(import_name)
1785
1793
  except (SystemExit, KeyboardInterrupt):
1786
1794
  raise
1787
1795
  except BaseException as e:
@@ -1821,13 +1829,17 @@ def get_library_doc(
1821
1829
 
1822
1830
  lib = None
1823
1831
  try:
1824
- lib = get_test_library(
1832
+ lib = _get_test_library(
1825
1833
  libcode,
1826
1834
  source,
1827
1835
  library_name,
1828
1836
  args,
1829
1837
  create_handlers=False,
1830
- variables=robot_variables,
1838
+ variables=(
1839
+ robot_variables
1840
+ if robot_variables is not None
1841
+ else resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
1842
+ ),
1831
1843
  )
1832
1844
  if get_robot_version() < (7, 0):
1833
1845
  _ = lib.get_instance()
@@ -1847,7 +1859,7 @@ def get_library_doc(
1847
1859
 
1848
1860
  if args:
1849
1861
  try:
1850
- lib = get_test_library(libcode, source, library_name, (), create_handlers=False)
1862
+ lib = _get_test_library(libcode, source, library_name, (), create_handlers=False)
1851
1863
  if get_robot_version() < (7, 0):
1852
1864
  _ = lib.get_instance()
1853
1865
  else:
@@ -1862,6 +1874,10 @@ def get_library_doc(
1862
1874
  libdoc = LibraryDoc(
1863
1875
  name=library_name,
1864
1876
  source=real_source,
1877
+ line_no=lib.lineno if lib is not None else -1,
1878
+ version=str(lib.version) if lib is not None else "",
1879
+ scope=str(lib.scope) if lib is not None else ROBOT_DEFAULT_SCOPE,
1880
+ doc_format=(str(lib.doc_format) or ROBOT_DOC_FORMAT) if lib is not None else ROBOT_DOC_FORMAT,
1865
1881
  module_spec=(
1866
1882
  module_spec
1867
1883
  if module_spec is not None
@@ -1870,16 +1886,33 @@ def get_library_doc(
1870
1886
  else None
1871
1887
  ),
1872
1888
  python_path=sys.path,
1873
- line_no=lib.lineno if lib is not None else -1,
1874
- doc=str(lib.doc) if lib is not None else "",
1875
- version=str(lib.version) if lib is not None else "",
1876
- scope=str(lib.scope) if lib is not None else ROBOT_DEFAULT_SCOPE,
1877
- doc_format=(str(lib.doc_format) or ROBOT_DOC_FORMAT) if lib is not None else ROBOT_DOC_FORMAT,
1878
1889
  member_name=module_spec.member_name if module_spec is not None else None,
1879
1890
  )
1880
1891
 
1881
1892
  if lib is not None:
1882
1893
  try:
1894
+
1895
+ def _get(handler: Callable[[], _T]) -> Optional[_T]:
1896
+ try:
1897
+ return handler()
1898
+ except (SystemExit, KeyboardInterrupt):
1899
+ raise
1900
+ except BaseException as e:
1901
+ errors.append(
1902
+ error_from_exception(
1903
+ e,
1904
+ source or module_spec.origin if module_spec is not None else None,
1905
+ (
1906
+ 1
1907
+ if source is not None or module_spec is not None and module_spec.origin is not None
1908
+ else None
1909
+ ),
1910
+ )
1911
+ )
1912
+ return None
1913
+
1914
+ libdoc.doc = _get(lambda: str(lib.doc) if lib is not None else "") or ""
1915
+
1883
1916
  if get_robot_version() < (7, 0):
1884
1917
  libdoc.has_listener = lib.has_listener
1885
1918
 
@@ -1909,10 +1942,10 @@ def get_library_doc(
1909
1942
  keywords=[
1910
1943
  KeywordDoc(
1911
1944
  name=libdoc.name,
1912
- arguments=[ArgumentInfo.from_robot(a) for a in kw[0].args],
1913
- doc=kw[0].doc,
1914
- tags=list(kw[0].tags),
1915
- source=kw[0].source,
1945
+ arguments=_get(lambda: [ArgumentInfo.from_robot(a) for a in kw[0].args]) or [],
1946
+ doc=_get(lambda: kw[0].doc) or "",
1947
+ tags=_get(lambda: list(kw[0].tags)) or [],
1948
+ source=_get(lambda: kw[0].source) or "",
1916
1949
  line_no=kw[0].lineno if kw[0].lineno is not None else -1,
1917
1950
  col_offset=-1,
1918
1951
  end_col_offset=-1,
@@ -1923,20 +1956,23 @@ def get_library_doc(
1923
1956
  longname=f"{libdoc.name}.{kw[0].name}",
1924
1957
  doc_format=str(lib.doc_format) or ROBOT_DOC_FORMAT,
1925
1958
  is_initializer=True,
1926
- arguments_spec=ArgumentSpec.from_robot_argument_spec(
1927
- kw[1].arguments if get_robot_version() < (7, 0) else kw[1].args
1959
+ arguments_spec=_get(
1960
+ lambda: ArgumentSpec.from_robot_argument_spec(
1961
+ kw[1].arguments if get_robot_version() < (7, 0) else kw[1].args
1962
+ )
1928
1963
  ),
1929
1964
  )
1930
1965
  for kw in init_keywords
1931
1966
  ]
1932
1967
  )
1933
1968
 
1934
- logger = Logger()
1935
- lib.logger = logger
1969
+ logger = _Logger()
1936
1970
 
1937
1971
  if get_robot_version() < (7, 0):
1972
+ lib.logger = logger
1938
1973
  lib.create_handlers()
1939
1974
  else:
1975
+ lib._logger = logger
1940
1976
  lib.create_keywords()
1941
1977
 
1942
1978
  for m in logger.messages:
@@ -1969,10 +2005,10 @@ def get_library_doc(
1969
2005
  keywords=[
1970
2006
  KeywordDoc(
1971
2007
  name=kw[0].name,
1972
- arguments=[ArgumentInfo.from_robot(a) for a in kw[0].args],
1973
- doc=kw[0].doc,
1974
- tags=list(kw[0].tags),
1975
- source=kw[0].source,
2008
+ arguments=_get(lambda: [ArgumentInfo.from_robot(a) for a in kw[0].args]) or [],
2009
+ doc=_get(lambda: kw[0].doc) or "",
2010
+ tags=_get(lambda: list(kw[0].tags)) or [],
2011
+ source=_get(lambda: kw[0].source) or "",
1976
2012
  line_no=kw[0].lineno if kw[0].lineno is not None else -1,
1977
2013
  col_offset=-1,
1978
2014
  end_col_offset=-1,
@@ -1987,21 +2023,26 @@ def get_library_doc(
1987
2023
  is_registered_run_keyword=RUN_KW_REGISTER.is_run_keyword(libdoc.name, kw[0].name),
1988
2024
  args_to_process=get_args_to_process(libdoc.name, kw[0].name),
1989
2025
  deprecated=kw[0].deprecated,
1990
- arguments_spec=(
1991
- ArgumentSpec.from_robot_argument_spec(
1992
- kw[1].arguments if get_robot_version() < (7, 0) else kw[1].args
2026
+ arguments_spec=_get(
2027
+ lambda: (
2028
+ ArgumentSpec.from_robot_argument_spec(
2029
+ kw[1].arguments if get_robot_version() < (7, 0) else kw[1].args
2030
+ )
2031
+ if not kw[1].is_error_handler
2032
+ else None
1993
2033
  )
1994
- if not kw[1].is_error_handler
1995
- else None
1996
2034
  ),
1997
- return_type=(
1998
- (
1999
- str(kw[1].args.return_type)
2000
- if kw[1].args.return_type is not None and kw[1].args.return_type is not type(None)
2035
+ return_type=_get(
2036
+ lambda: (
2037
+ (
2038
+ str(kw[1].args.return_type)
2039
+ if kw[1].args.return_type is not None
2040
+ and kw[1].args.return_type is not type(None)
2041
+ else None
2042
+ )
2043
+ if get_robot_version() >= (7, 0)
2001
2044
  else None
2002
2045
  )
2003
- if get_robot_version() >= (7, 0)
2004
- else None
2005
2046
  ),
2006
2047
  )
2007
2048
  for kw in keyword_docs
@@ -2086,9 +2127,8 @@ def _find_variables_internal(
2086
2127
 
2087
2128
  _update_env(working_dir)
2088
2129
 
2089
- robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2090
-
2091
2130
  if contains_variable(name, "$@&%"):
2131
+ robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2092
2132
  try:
2093
2133
  name = robot_variables.replace_string(name, ignore_errors=False)
2094
2134
  except DataError as error:
@@ -2109,12 +2149,18 @@ def resolve_args(
2109
2149
  command_line_variables: Optional[Dict[str, Optional[Any]]] = None,
2110
2150
  variables: Optional[Dict[str, Optional[Any]]] = None,
2111
2151
  ) -> Tuple[Any, ...]:
2112
- robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2152
+ # robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2153
+ robot_variables: Any = None
2113
2154
 
2114
2155
  result = []
2115
2156
  for arg in args:
2116
2157
  if isinstance(arg, str):
2117
- result.append(robot_variables.replace_string(arg, ignore_errors=True))
2158
+ if contains_variable(arg, "$@&%"):
2159
+ if robot_variables is None:
2160
+ robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2161
+ result.append(robot_variables.replace_string(arg, ignore_errors=True))
2162
+ else:
2163
+ result.append(arg)
2118
2164
  else:
2119
2165
  result.append(arg)
2120
2166
 
@@ -2389,8 +2435,8 @@ def find_file(
2389
2435
  ) -> str:
2390
2436
  _update_env(working_dir)
2391
2437
 
2392
- robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2393
2438
  if contains_variable(name, "$@&%"):
2439
+ robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2394
2440
  try:
2395
2441
  name = robot_variables.replace_string(name, ignore_errors=False)
2396
2442
  except DataError as error:
@@ -2492,7 +2538,7 @@ def complete_library_import(
2492
2538
  if e not in DEFAULT_LIBRARIES
2493
2539
  ]
2494
2540
 
2495
- if name is not None:
2541
+ if name is not None and contains_variable(name, "$@&%"):
2496
2542
  robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2497
2543
 
2498
2544
  name = robot_variables.replace_string(name, ignore_errors=True)
@@ -2568,7 +2614,7 @@ def complete_resource_import(
2568
2614
 
2569
2615
  result: List[CompleteResult] = []
2570
2616
 
2571
- if name is not None:
2617
+ if name is not None and contains_variable(name, "$@&%"):
2572
2618
  robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2573
2619
 
2574
2620
  name = robot_variables.replace_string(name, ignore_errors=True)
@@ -2608,7 +2654,7 @@ def complete_variables_import(
2608
2654
 
2609
2655
  result: List[CompleteResult] = []
2610
2656
 
2611
- if name is not None:
2657
+ if name is not None and contains_variable(name, "$@&%"):
2612
2658
  robot_variables = resolve_robot_variables(working_dir, base_dir, command_line_variables, variables)
2613
2659
 
2614
2660
  name = robot_variables.replace_string(name, ignore_errors=True)
@@ -2656,15 +2702,16 @@ def get_model_doc(
2656
2702
  append_model_errors: bool = True,
2657
2703
  ) -> LibraryDoc:
2658
2704
  errors: List[Error] = []
2659
- keyword_name_nodes: List[KeywordName] = []
2660
- keywords_nodes: List[Keyword] = []
2661
- for node in ast.walk(model):
2662
- if isinstance(node, Keyword):
2663
- keywords_nodes.append(node)
2664
- if isinstance(node, KeywordName):
2665
- keyword_name_nodes.append(node)
2666
-
2667
- error = node.error if isinstance(node, HasError) else None
2705
+ keyword_name_nodes: Dict[int, KeywordName] = {}
2706
+ keywords_nodes: Dict[int, Keyword] = {}
2707
+ for node in iter_nodes(model):
2708
+ if cached_isinstance(node, Keyword):
2709
+ node.lineno
2710
+ keywords_nodes[node.lineno] = node
2711
+ if cached_isinstance(node, KeywordName):
2712
+ keyword_name_nodes[node.lineno] = node
2713
+
2714
+ error = getattr(node, "error", None)
2668
2715
  if error is not None:
2669
2716
  errors.append(
2670
2717
  Error(
@@ -2675,7 +2722,7 @@ def get_model_doc(
2675
2722
  )
2676
2723
  )
2677
2724
  if append_model_errors:
2678
- node_errors = node.errors if isinstance(node, HasErrors) else None
2725
+ node_errors = getattr(node, "errors", None)
2679
2726
  if node_errors is not None:
2680
2727
  for e in node_errors:
2681
2728
  errors.append(
@@ -2688,16 +2735,15 @@ def get_model_doc(
2688
2735
  )
2689
2736
 
2690
2737
  def get_keyword_name_token_from_line(line: int) -> Optional[Token]:
2691
- for keyword_name in keyword_name_nodes:
2692
- if keyword_name.lineno == line:
2693
- return cast(Token, keyword_name.get_token(RobotToken.KEYWORD_NAME))
2694
-
2695
- return None
2738
+ keyword_name = keyword_name_nodes.get(line, None)
2739
+ if keyword_name is None:
2740
+ return None
2741
+ return cast(Token, keyword_name.get_token(RobotToken.KEYWORD_NAME))
2696
2742
 
2697
2743
  def get_argument_definitions_from_line(
2698
2744
  line: int,
2699
2745
  ) -> List[ArgumentDefinition]:
2700
- keyword_node = next((k for k in keywords_nodes if k.lineno == line), None)
2746
+ keyword_node = keywords_nodes.get(line, None)
2701
2747
  if keyword_node is None:
2702
2748
  return []
2703
2749