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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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