Skip to content

Commit 3603ff6

Browse files
committed
perf(analyzer): cache embedded arguments and some more little perf tweaks
1 parent 77ce8f1 commit 3603ff6

File tree

5 files changed

+65
-50
lines changed

5 files changed

+65
-50
lines changed

packages/robot/src/robotcode/robot/diagnostics/keyword_finder.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import functools
12
import re
23
from itertools import chain
34
from typing import TYPE_CHECKING, Dict, Iterable, Iterator, List, NamedTuple, Optional, Sequence, Tuple
@@ -59,7 +60,6 @@ def __init__(self, namespace: "Namespace", library_doc: LibraryDoc) -> None:
5960
self._all_keywords: Optional[List[LibraryEntry]] = None
6061
self._resource_keywords: Optional[List[ResourceEntry]] = None
6162
self._library_keywords: Optional[List[LibraryEntry]] = None
62-
self._bdd_prefix_regexp: Optional["re.Pattern[str]"] = None
6363

6464
def reset_diagnostics(self) -> None:
6565
self.diagnostics = []
@@ -459,20 +459,18 @@ def _create_custom_and_standard_keyword_conflict_warning_message(
459459
f"or '{'' if standard[0] is None else standard[0].alias or standard[0].name}.{standard[1].name}'."
460460
)
461461

462-
@property
462+
@functools.cached_property
463463
def bdd_prefix_regexp(self) -> "re.Pattern[str]":
464-
if not self._bdd_prefix_regexp:
465-
prefixes = (
466-
"|".join(
467-
self.namespace.languages.bdd_prefixes
468-
if self.namespace.languages is not None
469-
else ["given", "when", "then", "and", "but"]
470-
)
471-
.replace(" ", r"\s")
472-
.lower()
464+
prefixes = (
465+
"|".join(
466+
self.namespace.languages.bdd_prefixes
467+
if self.namespace.languages is not None
468+
else ["given", "when", "then", "and", "but"]
473469
)
474-
self._bdd_prefix_regexp = re.compile(rf"({prefixes})\s", re.IGNORECASE)
475-
return self._bdd_prefix_regexp
470+
.replace(" ", r"\s")
471+
.lower()
472+
)
473+
return re.compile(rf"({prefixes})\s", re.IGNORECASE)
476474

477475
def _get_bdd_style_keyword(self, name: str) -> Optional[KeywordDoc]:
478476
match = self.bdd_prefix_regexp.match(name)

packages/robot/src/robotcode/robot/diagnostics/library_doc.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import ast
4+
import functools
45
import hashlib
56
import importlib
67
import importlib.util
@@ -197,14 +198,29 @@ def convert_from_rest(text: str) -> str:
197198
return text
198199

199200

201+
if get_robot_version() >= (6, 0):
202+
203+
@functools.lru_cache(maxsize=None)
204+
def _get_embedded_arguments(name: str) -> Any:
205+
try:
206+
return EmbeddedArguments.from_name(name)
207+
except (VariableError, DataError):
208+
return ()
209+
210+
else:
211+
212+
@functools.lru_cache(maxsize=None)
213+
def _get_embedded_arguments(name: str) -> Any:
214+
try:
215+
return EmbeddedArguments(name)
216+
except (VariableError, DataError):
217+
return ()
218+
219+
200220
def is_embedded_keyword(name: str) -> bool:
201221
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
222+
if _get_embedded_arguments(name):
223+
return True
208224
except (VariableError, DataError):
209225
return True
210226

@@ -235,18 +251,22 @@ def normalized_name(self) -> str:
235251
def embedded_arguments(self) -> Any:
236252
if self._embedded_arguments is None:
237253
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 = ()
254+
self._embedded_arguments = _get_embedded_arguments(self.name)
245255
else:
246256
self._embedded_arguments = ()
247257

248258
return self._embedded_arguments
249259

260+
if get_robot_version() >= (6, 0):
261+
262+
def __match_embedded(self, name: str) -> bool:
263+
return self.embedded_arguments.match(name) is not None
264+
265+
else:
266+
267+
def __match_embedded(self, name: str) -> bool:
268+
return self.embedded_arguments.name.match(name) is not None
269+
250270
def __eq__(self, o: object) -> bool:
251271
if cached_isinstance(o, KeywordMatcher):
252272
if self._is_namespace != o._is_namespace:
@@ -261,10 +281,7 @@ def __eq__(self, o: object) -> bool:
261281
return False
262282

263283
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
284+
return self.__match_embedded(o)
268285

269286
return self.normalized_name == str(normalize_namespace(o) if self._is_namespace else normalize(o))
270287

@@ -935,8 +952,6 @@ def __getitem__(self, key: str) -> KeywordDoc:
935952
)
936953

937954
def __contains__(self, _x: object) -> bool:
938-
if not isinstance(_x, KeywordMatcher):
939-
_x = KeywordMatcher(str(_x))
940955
return any(k == _x for k in self._matchers.keys())
941956

942957
def __len__(self) -> int:

packages/robot/src/robotcode/robot/diagnostics/namespace.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ def get_namespaces(self) -> Dict[KeywordMatcher, List[LibraryEntry]]:
893893
self._namespaces[KeywordMatcher(v.alias or v.name or v.import_name, is_namespace=True)].append(v)
894894
for v in (self.get_resources()).values():
895895
self._namespaces[KeywordMatcher(v.alias or v.name or v.import_name, is_namespace=True)].append(v)
896+
896897
return self._namespaces
897898

898899
def get_resources(self) -> Dict[str, ResourceEntry]:
@@ -1793,11 +1794,10 @@ def iter_all_keywords(self) -> Iterator[KeywordDoc]:
17931794

17941795
libdoc = self.get_library_doc()
17951796

1796-
for doc in itertools.chain(
1797+
yield from itertools.chain(
17971798
self.get_imported_keywords(),
17981799
libdoc.keywords if libdoc is not None else [],
1799-
):
1800-
yield doc
1800+
)
18011801

18021802
@_logger.call
18031803
def get_keywords(self) -> List[KeywordDoc]:

packages/robot/src/robotcode/robot/diagnostics/namespace_analyzer.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,20 @@ def _append_diagnostics(
531531
)
532532
)
533533

534+
KEYWORDS_WITH_EXPRESSIONS = [
535+
"BuiltIn.Evaluate",
536+
"BuiltIn.Should Be True",
537+
"BuiltIn.Should Not Be True",
538+
"BuiltIn.Skip If",
539+
"BuiltIn.Continue For Loop If",
540+
"BuiltIn.Exit For Loop If",
541+
"BuiltIn.Return From Keyword If",
542+
"BuiltIn.Run Keyword And Return If",
543+
"BuiltIn.Pass Execution If",
544+
"BuiltIn.Run Keyword If",
545+
"BuiltIn.Run Keyword Unless",
546+
]
547+
534548
def _analyze_keyword_call(
535549
self,
536550
node: ast.AST,
@@ -708,19 +722,7 @@ def _analyze_keyword_call(
708722
)
709723

710724
if result is not None:
711-
if result.longname in [
712-
"BuiltIn.Evaluate",
713-
"BuiltIn.Should Be True",
714-
"BuiltIn.Should Not Be True",
715-
"BuiltIn.Skip If",
716-
"BuiltIn.Continue For Loop If",
717-
"BuiltIn.Exit For Loop If",
718-
"BuiltIn.Return From Keyword If",
719-
"BuiltIn.Run Keyword And Return If",
720-
"BuiltIn.Pass Execution If",
721-
"BuiltIn.Run Keyword If",
722-
"BuiltIn.Run Keyword Unless",
723-
]:
725+
if result.longname in self.KEYWORDS_WITH_EXPRESSIONS:
724726
tokens = argument_tokens
725727
if tokens and (token := tokens[0]):
726728
self._analyze_token_expression_variables(token)

packages/robot/src/robotcode/robot/utils/match.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
_transform_table = str.maketrans("", "", "_ ")
44

55

6-
@lru_cache(maxsize=5000)
6+
@lru_cache(maxsize=None)
77
def normalize(text: str) -> str:
88
# return text.lower().replace("_", "").replace(" ", "")
99
return text.casefold().translate(_transform_table)
1010

1111

12-
@lru_cache(maxsize=5000)
12+
@lru_cache(maxsize=None)
1313
def normalize_namespace(text: str) -> str:
1414
return text.lower().replace(" ", "")
1515

0 commit comments

Comments
 (0)