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,3 +1,5 @@
1
+ import functools
2
+ import re
1
3
  from itertools import chain
2
4
  from typing import TYPE_CHECKING, Dict, Iterable, Iterator, List, NamedTuple, Optional, Sequence, Tuple
3
5
 
@@ -42,6 +44,8 @@ class KeywordFinder:
42
44
  self.self_library_doc = library_doc
43
45
 
44
46
  self.diagnostics: List[DiagnosticsEntry] = []
47
+ self.result_bdd_prefix: Optional[str] = None
48
+
45
49
  self.multiple_keywords_result: Optional[List[KeywordDoc]] = None
46
50
  self._cache: Dict[
47
51
  Tuple[Optional[str], bool],
@@ -49,17 +53,20 @@ class KeywordFinder:
49
53
  Optional[KeywordDoc],
50
54
  List[DiagnosticsEntry],
51
55
  Optional[List[KeywordDoc]],
56
+ Optional[str],
52
57
  ],
53
58
  ] = {}
54
- self.handle_bdd_style = True
59
+
55
60
  self._all_keywords: Optional[List[LibraryEntry]] = None
56
- self._resource_keywords: Optional[List[ResourceEntry]] = None
57
- self._library_keywords: Optional[List[LibraryEntry]] = None
61
+ self._resource_imports: Optional[List[ResourceEntry]] = None
62
+ self._library_imports: Optional[List[LibraryEntry]] = None
58
63
 
59
64
  def reset_diagnostics(self) -> None:
60
65
  self.diagnostics = []
61
66
  self.multiple_keywords_result = None
67
+ self.result_bdd_prefix = None
62
68
 
69
+ # TODO: make this threadsafe
63
70
  def find_keyword(
64
71
  self,
65
72
  name: Optional[str],
@@ -70,17 +77,16 @@ class KeywordFinder:
70
77
  try:
71
78
  self.reset_diagnostics()
72
79
 
73
- self.handle_bdd_style = handle_bdd_style
74
-
75
- cached = self._cache.get((name, self.handle_bdd_style), None)
80
+ cached = self._cache.get((name, handle_bdd_style), None)
76
81
 
77
82
  if cached is not None:
78
83
  self.diagnostics = cached[1]
79
84
  self.multiple_keywords_result = cached[2]
85
+ self.result_bdd_prefix = cached[3]
80
86
  return cached[0]
81
87
 
82
88
  try:
83
- result = self._find_keyword(name)
89
+ result = self._find_keyword(name, handle_bdd_style)
84
90
  if result is None:
85
91
  self.diagnostics.append(
86
92
  DiagnosticsEntry(
@@ -99,17 +105,22 @@ class KeywordFinder:
99
105
  result = None
100
106
  self.diagnostics.append(DiagnosticsEntry(str(e), DiagnosticSeverity.ERROR, Error.KEYWORD_ERROR))
101
107
 
102
- self._cache[(name, self.handle_bdd_style)] = (
108
+ self._cache[(name, handle_bdd_style)] = (
103
109
  result,
104
110
  self.diagnostics,
105
111
  self.multiple_keywords_result,
112
+ self.result_bdd_prefix,
106
113
  )
107
114
 
108
115
  return result
109
116
  except CancelSearchError:
110
117
  return None
111
118
 
112
- def _find_keyword(self, name: Optional[str]) -> Optional[KeywordDoc]:
119
+ def _find_keyword(
120
+ self,
121
+ name: Optional[str],
122
+ handle_bdd_style: bool = True,
123
+ ) -> Optional[KeywordDoc]:
113
124
  if not name:
114
125
  self.diagnostics.append(
115
126
  DiagnosticsEntry(
@@ -129,14 +140,21 @@ class KeywordFinder:
129
140
  )
130
141
  raise CancelSearchError
131
142
 
132
- result = self._get_keyword_from_self(name)
143
+ result: Optional[KeywordDoc] = None
144
+
145
+ if get_robot_version() >= (7, 0) and handle_bdd_style:
146
+ result = self._get_bdd_style_keyword(name)
147
+
148
+ if not result:
149
+ result = self._get_keyword_from_self(name)
150
+
133
151
  if not result and "." in name:
134
152
  result = self._get_explicit_keyword(name)
135
153
 
136
154
  if not result:
137
155
  result = self._get_implicit_keyword(name)
138
156
 
139
- if not result and self.handle_bdd_style:
157
+ if get_robot_version() < (7, 0) and not result and handle_bdd_style:
140
158
  return self._get_bdd_style_keyword(name)
141
159
 
142
160
  return result
@@ -264,6 +282,9 @@ class KeywordFinder:
264
282
  def _select_best_matches(
265
283
  self, entries: List[Tuple[Optional[LibraryEntry], KeywordDoc]]
266
284
  ) -> List[Tuple[Optional[LibraryEntry], KeywordDoc]]:
285
+ if len(entries) < 2:
286
+ return entries
287
+
267
288
  normal = [hand for hand in entries if not hand[1].is_embedded]
268
289
  if normal:
269
290
  return normal
@@ -291,23 +312,23 @@ class KeywordFinder:
291
312
  other: Tuple[Optional[LibraryEntry], KeywordDoc],
292
313
  ) -> bool:
293
314
  return (
294
- other[1].matcher.embedded_arguments.match(candidate[1].name) is not None
315
+ other[1].matcher.embedded_arguments is not None
316
+ and candidate[1].matcher.embedded_arguments is not None
317
+ and other[1].matcher.embedded_arguments.match(candidate[1].name) is not None
295
318
  and candidate[1].matcher.embedded_arguments.match(other[1].name) is None
296
319
  )
297
320
 
298
321
  def _get_keyword_from_resource_files(self, name: str) -> Optional[KeywordDoc]:
299
- if self._resource_keywords is None:
300
- self._resource_keywords = list(chain(self.namespace._resources.values()))
322
+ if self._resource_imports is None:
323
+ self._resource_imports = list(chain(self.namespace._resources.values()))
301
324
 
302
325
  if get_robot_version() >= (6, 0):
303
- found: List[Tuple[Optional[LibraryEntry], KeywordDoc]] = []
304
- for v in self._resource_keywords:
305
- r = v.library_doc.keywords.get_all(name)
306
- if r:
307
- found.extend([(v, k) for k in r])
326
+ found: List[Tuple[Optional[LibraryEntry], KeywordDoc]] = [
327
+ (v, k) for v in self._resource_imports for k in v.library_doc.keywords.iter_all(name)
328
+ ]
308
329
  else:
309
330
  found = []
310
- for k in self._resource_keywords:
331
+ for k in self._resource_imports:
311
332
  s = k.library_doc.keywords.get(name, None)
312
333
  if s is not None:
313
334
  found.append((k, s))
@@ -352,19 +373,18 @@ class KeywordFinder:
352
373
  return entries
353
374
 
354
375
  def _get_keyword_from_libraries(self, name: str) -> Optional[KeywordDoc]:
355
- if self._library_keywords is None:
356
- self._library_keywords = list(chain(self.namespace._libraries.values()))
376
+ if self._library_imports is None:
377
+ self._library_imports = list(chain(self.namespace._libraries.values()))
357
378
 
358
379
  if get_robot_version() >= (6, 0):
359
- found: List[Tuple[Optional[LibraryEntry], KeywordDoc]] = []
360
- for v in self._library_keywords:
361
- r = v.library_doc.keywords.get_all(name)
362
- if r:
363
- found.extend([(v, k) for k in r])
380
+ found: List[Tuple[Optional[LibraryEntry], KeywordDoc]] = [
381
+ (v, k) for v in self._library_imports for k in v.library_doc.keywords.iter_all(name)
382
+ ]
383
+
364
384
  else:
365
385
  found = []
366
386
 
367
- for k in self._library_keywords:
387
+ for k in self._library_imports:
368
388
  s = k.library_doc.keywords.get(name, None)
369
389
  if s is not None:
370
390
  found.append((k, s))
@@ -438,21 +458,27 @@ class KeywordFinder:
438
458
  f"or '{'' if standard[0] is None else standard[0].alias or standard[0].name}.{standard[1].name}'."
439
459
  )
440
460
 
461
+ @functools.cached_property
462
+ def bdd_prefix_regexp(self) -> "re.Pattern[str]":
463
+ prefixes = (
464
+ "|".join(
465
+ self.namespace.languages.bdd_prefixes
466
+ if self.namespace.languages is not None
467
+ else ["given", "when", "then", "and", "but"]
468
+ )
469
+ .replace(" ", r"\s")
470
+ .lower()
471
+ )
472
+ return re.compile(rf"({prefixes})\s", re.IGNORECASE)
473
+
441
474
  def _get_bdd_style_keyword(self, name: str) -> Optional[KeywordDoc]:
442
- if get_robot_version() < (6, 0):
443
- lower = name.lower()
444
- for prefix in ["given ", "when ", "then ", "and ", "but "]:
445
- if lower.startswith(prefix):
446
- return self._find_keyword(name[len(prefix) :])
447
- return None
475
+ match = self.bdd_prefix_regexp.match(name)
476
+ if match:
477
+ result = self._find_keyword(
478
+ name[match.end() :], handle_bdd_style=False if get_robot_version() >= (7, 0) else True
479
+ )
480
+ if result:
481
+ self.result_bdd_prefix = str(match.group(0))
448
482
 
449
- parts = name.split()
450
- if len(parts) < 2:
451
- return None
452
- for index in range(1, len(parts)):
453
- prefix = " ".join(parts[:index]).title()
454
- if prefix.title() in (
455
- self.namespace.languages.bdd_prefixes if self.namespace.languages is not None else DEFAULT_BDD_PREFIXES
456
- ):
457
- return self._find_keyword(" ".join(parts[index:]))
483
+ return result
458
484
  return None