robotcode-robot 0.83.2__py3-none-any.whl → 0.84.0__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 +1 @@
1
- __version__ = "0.83.2"
1
+ __version__ = "0.84.0"
@@ -291,8 +291,9 @@ class BaseOptions(ValidateMixin):
291
291
  for key, item in value.items():
292
292
  append_name(field)
293
293
  if isinstance(item, list):
294
- separator = ";" if any(True for s in item if ":" in s) else ":"
295
- result.append(f"{key}{separator if item else ''}{separator.join(item)}")
294
+ str_item = [str(i) for i in item]
295
+ separator = ";" if any(True for s in str_item if ":" in s) else ":"
296
+ result.append(f"{key}{separator if item else ''}{separator.join(str_item)}")
296
297
  else:
297
298
  result.append(f"{key}:{item}")
298
299
  else:
@@ -0,0 +1,201 @@
1
+ import functools
2
+ import re as re
3
+ from ast import AST
4
+ from collections import defaultdict
5
+ from dataclasses import dataclass
6
+ from typing import Dict, List, Optional, Set, Union
7
+
8
+ from robot.parsing.lexer.tokens import Token
9
+ from robot.parsing.model.blocks import Block, File
10
+ from robot.parsing.model.statements import Comment, Statement
11
+ from robotcode.core.lsp.types import Diagnostic, DiagnosticSeverity
12
+
13
+ from ..utils.visitor import Visitor
14
+
15
+ ACTIONS = ["ignore", "error", "warn", "information", "hint", "reset"]
16
+
17
+ ROBOTCODE_ACTION_AND_CODES_PATTERN = re.compile(rf"(?P<action>{'|'.join(ACTIONS)})(\[(?P<codes>[^\]]*?)\])?")
18
+
19
+
20
+ @dataclass
21
+ class RulesAndCodes:
22
+ codes: Dict[Union[str, int], Set[int]]
23
+ actions: Dict[int, Dict[Union[str, int], str]]
24
+
25
+
26
+ _translation_table = str.maketrans("", "", "_- ")
27
+
28
+ ROBOTCODE_MARKER = "robotcode:"
29
+
30
+
31
+ class DisablersVisitor(Visitor):
32
+
33
+ def __init__(self) -> None:
34
+ super().__init__()
35
+
36
+ self._file_lineno = 0
37
+ self._file_end_lineno = 0
38
+ self.current_block: Optional[Block] = None
39
+ self.rules_and_codes: RulesAndCodes = RulesAndCodes(defaultdict(set), defaultdict(dict))
40
+
41
+ @property
42
+ def file_lineno(self) -> int:
43
+ return self._file_lineno
44
+
45
+ @property
46
+ def file_end_lineno(self) -> int:
47
+ return self._file_end_lineno
48
+
49
+ def visit_File(self, node: File) -> None: # noqa: N802
50
+ self._file_lineno = node.lineno - 1
51
+ self._file_end_lineno = node.end_lineno - 1
52
+
53
+ self.generic_visit(node)
54
+
55
+ def visit_Comment(self, node: Comment) -> None: # noqa: N802
56
+ self._handle_comment(node)
57
+
58
+ self.generic_visit(node)
59
+
60
+ def visit_Block(self, node: Block) -> None: # noqa: N802
61
+ self.current_block = node
62
+ self.generic_visit(node)
63
+
64
+ def visit_Statement(self, node: Statement) -> None: # noqa: N802
65
+ self._handle_statement_comments(node)
66
+ self.generic_visit(node)
67
+
68
+ def _parse_robotcode_disabler(self, comment: str) -> Dict[str, List[str]]:
69
+ result: Dict[str, List[str]] = {}
70
+
71
+ comment = comment.strip()
72
+ m = ROBOTCODE_ACTION_AND_CODES_PATTERN.match(comment)
73
+ if m is None:
74
+ return result
75
+
76
+ for m in ROBOTCODE_ACTION_AND_CODES_PATTERN.finditer(comment):
77
+ action = m.group("action")
78
+ messages = m.group("codes")
79
+ result[action] = (
80
+ [m.strip().translate(_translation_table).lower() for m in messages.split(",")]
81
+ if messages is not None
82
+ else ["*"]
83
+ )
84
+
85
+ return result
86
+
87
+ def _handle_statement_comments(self, node: Statement) -> None:
88
+ first_comment = True
89
+ has_marker = False
90
+
91
+ for token in node.get_tokens(Token.COMMENT):
92
+ value = token.value.strip()
93
+ if first_comment and value.startswith("#"):
94
+ value = value[1:].strip()
95
+ first_comment = False
96
+
97
+ if not value:
98
+ continue
99
+
100
+ if not has_marker and value.startswith(ROBOTCODE_MARKER):
101
+ has_marker = True
102
+ value = value[10:]
103
+
104
+ if not value:
105
+ continue
106
+
107
+ if has_marker:
108
+ actions = self._parse_robotcode_disabler(value)
109
+
110
+ if not actions:
111
+ break
112
+
113
+ for action, codes in actions.items():
114
+ for code in codes:
115
+ self.rules_and_codes.codes[code].add(token.lineno - 1)
116
+ self.rules_and_codes.actions[token.lineno - 1][code] = action
117
+
118
+ def _handle_comment(self, node: Comment) -> None:
119
+ first_comment = True
120
+ has_marker = False
121
+
122
+ start_lineno = node.lineno - 1
123
+ end_lineno = self.file_end_lineno
124
+
125
+ if node.tokens[0].type == Token.SEPARATOR and self.current_block is not None:
126
+ end_lineno = self.current_block.end_lineno - 1
127
+ for token in node.get_tokens(Token.COMMENT):
128
+ value = token.value.strip()
129
+ if first_comment and value.startswith("#"):
130
+ value = value[1:].strip()
131
+ first_comment = False
132
+
133
+ if not value:
134
+ continue
135
+
136
+ if not has_marker and value.startswith(ROBOTCODE_MARKER):
137
+ has_marker = True
138
+ value = value[10:]
139
+
140
+ if not value:
141
+ continue
142
+
143
+ if has_marker:
144
+ actions = self._parse_robotcode_disabler(value)
145
+
146
+ if not actions:
147
+ break
148
+
149
+ for action, codes in actions.items():
150
+ for code in codes:
151
+ self.rules_and_codes.codes[code].update(range(start_lineno, end_lineno + 1))
152
+ for i in range(start_lineno, end_lineno + 1):
153
+ self.rules_and_codes.actions[i][code] = action
154
+
155
+
156
+ class DiagnosticsModifier:
157
+ def __init__(self, model: AST) -> None:
158
+ self.model = model
159
+
160
+ @functools.cached_property
161
+ def rules_and_codes(self) -> RulesAndCodes:
162
+ visitor = DisablersVisitor()
163
+ visitor.visit(self.model)
164
+ return visitor.rules_and_codes
165
+
166
+ def modify_diagnostic(self, diagnostic: Diagnostic) -> Optional[Diagnostic]:
167
+ if diagnostic.code is not None:
168
+ code = (
169
+ str(diagnostic.code).translate(_translation_table).lower()
170
+ if diagnostic.code is not None
171
+ else "unknowncode"
172
+ )
173
+
174
+ lines = self.rules_and_codes.codes.get(code)
175
+
176
+ if lines is None or lines is not None and diagnostic.range.start.line not in lines:
177
+ code = "*"
178
+ lines = self.rules_and_codes.codes.get(code)
179
+
180
+ if lines is not None and diagnostic.range.start.line in lines:
181
+ actions = self.rules_and_codes.actions.get(diagnostic.range.start.line)
182
+ if actions is not None:
183
+ action = actions.get(code)
184
+ if action is not None:
185
+ if action == "ignore":
186
+ return None
187
+ if action == "reset":
188
+ pass # do nothing
189
+ elif action == "error":
190
+ diagnostic.severity = DiagnosticSeverity.ERROR
191
+ elif action == "warn":
192
+ diagnostic.severity = DiagnosticSeverity.WARNING
193
+ elif action == "information":
194
+ diagnostic.severity = DiagnosticSeverity.INFORMATION
195
+ elif action == "hint":
196
+ diagnostic.severity = DiagnosticSeverity.HINT
197
+
198
+ return diagnostic
199
+
200
+ def modify_diagnostics(self, diagnostics: List[Diagnostic]) -> List[Diagnostic]:
201
+ return [d for d in map(self.modify_diagnostic, diagnostics) if d is not None]
@@ -26,6 +26,7 @@ from robotcode.core.text_document import TextDocument
26
26
  from robotcode.core.uri import Uri
27
27
  from robotcode.core.utils.logging import LoggingDescriptor
28
28
  from robotcode.core.workspace import Workspace, WorkspaceFolder
29
+ from robotcode.robot.diagnostics.diagnostics_modifier import DiagnosticsModifier
29
30
 
30
31
  from ..config.model import RobotBaseProfile
31
32
  from ..utils import get_robot_version
@@ -453,9 +454,7 @@ class DocumentsCacheHelper:
453
454
  return result
454
455
 
455
456
  def get_only_initialized_namespace(self, document: TextDocument) -> Optional[Namespace]:
456
- result: Optional[Namespace] = document.get_data(self.INITIALIZED_NAMESPACE)
457
-
458
- return result
457
+ return cast(Optional[Namespace], document.get_data(self.INITIALIZED_NAMESPACE))
459
458
 
460
459
  def __get_namespace_for_document_type(
461
460
  self, document: TextDocument, document_type: Optional[DocumentType]
@@ -579,3 +578,9 @@ class DocumentsCacheHelper:
579
578
  def calc_cache_path(self, folder_uri: Uri) -> Path:
580
579
  # TODO: cache path should be configurable, save cache in vscode workspace folder or in robotcode cache folder
581
580
  return folder_uri.to_path()
581
+
582
+ def get_diagnostic_modifier(self, document: TextDocument) -> DiagnosticsModifier:
583
+ return document.get_cache(self.__get_diagnostic_modifier)
584
+
585
+ def __get_diagnostic_modifier(self, document: TextDocument) -> DiagnosticsModifier:
586
+ return DiagnosticsModifier(self.get_model(document, False))
@@ -12,7 +12,9 @@ from typing import (
12
12
  )
13
13
 
14
14
  from robot.parsing.lexer.tokens import Token
15
+ from robot.variables.search import search_variable
15
16
  from robotcode.core.lsp.types import Position, Range
17
+ from robotcode.robot.utils.match import normalize
16
18
 
17
19
  from ..utils.ast import range_from_token
18
20
 
@@ -131,9 +133,6 @@ class InvalidVariableError(Exception):
131
133
 
132
134
  class VariableMatcher:
133
135
  def __init__(self, name: str) -> None:
134
- from robot.variables.search import search_variable
135
- from robotcode.robot.utils.match import normalize
136
-
137
136
  self.name = name
138
137
 
139
138
  match = search_variable(name, "$@&%", ignore_errors=True)
@@ -146,9 +145,6 @@ class VariableMatcher:
146
145
  self.normalized_name = str(normalize(self.base))
147
146
 
148
147
  def __eq__(self, o: object) -> bool:
149
- from robot.utils.normalizing import normalize
150
- from robot.variables.search import search_variable
151
-
152
148
  if isinstance(o, VariableMatcher):
153
149
  return o.normalized_name == self.normalized_name
154
150
 
@@ -31,3 +31,5 @@ class Error:
31
31
  DEPRECATED_FORCE_TAG = "DeprecatedForceTag"
32
32
  IMPORT_REQUIRES_VALUE = "ImportRequiresValue"
33
33
  KEYWORD_ERROR = "KeywordError"
34
+ MULTIPLE_KEYWORDS = "MultipleKeywords"
35
+ CONFLICTING_LIBRARY_KEYWORDS = "ConflictingLibraryKeywords"
@@ -86,10 +86,10 @@ from robotcode.robot.utils.match import normalize, normalize_namespace
86
86
  from robotcode.robot.utils.stubs import HasError, HasErrors
87
87
 
88
88
  if get_robot_version() < (7, 0):
89
- from robot.running.handlers import _PythonHandler, _PythonInitHandler
90
- from robot.running.model import ResourceFile
91
- from robot.running.usererrorhandler import UserErrorHandler
92
- from robot.running.userkeyword import UserLibrary
89
+ from robot.running.handlers import _PythonHandler, _PythonInitHandler # pyright: ignore[reportMissingImports]
90
+ from robot.running.model import ResourceFile # pyright: ignore[reportMissingImports]
91
+ from robot.running.usererrorhandler import UserErrorHandler # pyright: ignore[reportMissingImports]
92
+ from robot.running.userkeyword import UserLibrary # pyright: ignore[reportMissingImports]
93
93
 
94
94
  robot_notset = ArgInfo.NOTSET
95
95
 
@@ -1960,7 +1960,7 @@ def get_library_doc(
1960
1960
  return_type=(
1961
1961
  (
1962
1962
  str(kw[1].args.return_type)
1963
- if kw[1].args.return_type is not None and kw[1].args.return_type != type(None)
1963
+ if kw[1].args.return_type is not None and kw[1].args.return_type is not type(None)
1964
1964
  else None
1965
1965
  )
1966
1966
  if get_robot_version() >= (7, 0)
@@ -2636,7 +2636,7 @@ def get_model_doc(
2636
2636
  message=error,
2637
2637
  type_name="ModelError",
2638
2638
  source=source,
2639
- line_no=node.lineno,
2639
+ line_no=node.lineno, # type: ignore
2640
2640
  )
2641
2641
  )
2642
2642
  if append_model_errors:
@@ -2648,7 +2648,7 @@ def get_model_doc(
2648
2648
  message=e,
2649
2649
  type_name="ModelError",
2650
2650
  source=source,
2651
- line_no=node.lineno,
2651
+ line_no=node.lineno, # type: ignore
2652
2652
  )
2653
2653
  )
2654
2654
 
@@ -1,7 +1,6 @@
1
1
  import ast
2
2
  import enum
3
3
  import itertools
4
- import re
5
4
  import time
6
5
  import weakref
7
6
  from collections import OrderedDict, defaultdict
@@ -97,9 +96,6 @@ from .library_doc import (
97
96
  resolve_robot_variables,
98
97
  )
99
98
 
100
- EXTRACT_COMMENT_PATTERN = re.compile(r".*(?:^ *|\t+| {2,})#(?P<comment>.*)$")
101
- ROBOTCODE_PATTERN = re.compile(r"(?P<marker>\brobotcode\b)\s*:\s*(?P<rule>\b\w+\b)")
102
-
103
99
 
104
100
  class DiagnosticsError(Exception):
105
101
  pass
@@ -454,7 +450,7 @@ class BlockVariableVisitor(OnlyArgumentsVisitor):
454
450
  source=self.namespace.source,
455
451
  )
456
452
 
457
- if var_name not in self._results or type(self._results[var_name]) != type(var):
453
+ if var_name not in self._results or type(self._results[var_name]) is not type(var):
458
454
  if isinstance(var, LocalVariableDefinition) or not any(
459
455
  l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
460
456
  ):
@@ -542,7 +538,7 @@ class BlockVariableVisitor(OnlyArgumentsVisitor):
542
538
  source=self.namespace.source,
543
539
  )
544
540
 
545
- if var_name not in self._results or type(self._results[var_name]) != type(var):
541
+ if var_name not in self._results or type(self._results[var_name]) is type(var):
546
542
  if isinstance(var, LocalVariableDefinition) or not any(
547
543
  l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
548
544
  ):
@@ -1803,8 +1799,6 @@ class Namespace:
1803
1799
  related_information: Optional[List[DiagnosticRelatedInformation]] = None,
1804
1800
  data: Optional[Any] = None,
1805
1801
  ) -> None:
1806
- if self._should_ignore(range):
1807
- return
1808
1802
 
1809
1803
  self._diagnostics.append(
1810
1804
  Diagnostic(
@@ -1840,12 +1834,7 @@ class Namespace:
1840
1834
  start_time = time.monotonic()
1841
1835
 
1842
1836
  try:
1843
- result = NamespaceAnalyzer(
1844
- self.model,
1845
- self,
1846
- self.create_finder(),
1847
- self.get_ignored_lines(self.document) if self.document is not None else [],
1848
- ).run()
1837
+ result = NamespaceAnalyzer(self.model, self, self.create_finder()).run()
1849
1838
 
1850
1839
  self._diagnostics += result.diagnostics
1851
1840
  self._keyword_references = result.keyword_references
@@ -1916,42 +1905,6 @@ class Namespace:
1916
1905
  handle_bdd_style=handle_bdd_style,
1917
1906
  )
1918
1907
 
1919
- @classmethod
1920
- def get_ignored_lines(cls, document: TextDocument) -> List[int]:
1921
- return document.get_cache(cls.__get_ignored_lines)
1922
-
1923
- @staticmethod
1924
- def __get_ignored_lines(document: TextDocument) -> List[int]:
1925
- result = []
1926
- lines = document.get_lines()
1927
- for line_no, line in enumerate(lines):
1928
- comment = EXTRACT_COMMENT_PATTERN.match(line)
1929
- if comment and comment.group("comment"):
1930
- for match in ROBOTCODE_PATTERN.finditer(comment.group("comment")):
1931
- if match.group("rule") == "ignore":
1932
- result.append(line_no)
1933
-
1934
- return result
1935
-
1936
- @classmethod
1937
- def should_ignore(cls, document: Optional[TextDocument], range: Range) -> bool:
1938
- return cls.__should_ignore(
1939
- cls.get_ignored_lines(document) if document is not None else [],
1940
- range,
1941
- )
1942
-
1943
- def _should_ignore(self, range: Range) -> bool:
1944
- if self._ignored_lines is None:
1945
- self._ignored_lines = self.get_ignored_lines(self.document) if self.document is not None else []
1946
-
1947
- return self.__should_ignore(self._ignored_lines, range)
1948
-
1949
- @staticmethod
1950
- def __should_ignore(lines: List[int], range: Range) -> bool:
1951
- import builtins
1952
-
1953
- return any(line_no in lines for line_no in builtins.range(range.start.line, range.end.line + 1))
1954
-
1955
1908
 
1956
1909
  class DiagnosticsEntry(NamedTuple):
1957
1910
  message: str
@@ -2083,7 +2036,7 @@ class KeywordFinder:
2083
2036
  DiagnosticsEntry(
2084
2037
  self._create_multiple_keywords_found_message(name, found, implicit=False),
2085
2038
  DiagnosticSeverity.ERROR,
2086
- Error.KEYWORD_ERROR,
2039
+ Error.MULTIPLE_KEYWORDS,
2087
2040
  )
2088
2041
  )
2089
2042
  raise CancelSearchError
@@ -2118,7 +2071,7 @@ class KeywordFinder:
2118
2071
  DiagnosticsEntry(
2119
2072
  self._create_multiple_keywords_found_message(name, found, implicit=False),
2120
2073
  DiagnosticSeverity.ERROR,
2121
- Error.KEYWORD_ERROR,
2074
+ Error.MULTIPLE_KEYWORDS,
2122
2075
  )
2123
2076
  )
2124
2077
  raise CancelSearchError
@@ -2266,7 +2219,7 @@ class KeywordFinder:
2266
2219
  DiagnosticsEntry(
2267
2220
  self._create_multiple_keywords_found_message(name, found),
2268
2221
  DiagnosticSeverity.ERROR,
2269
- Error.KEYWORD_ERROR,
2222
+ Error.MULTIPLE_KEYWORDS,
2270
2223
  )
2271
2224
  )
2272
2225
  raise CancelSearchError
@@ -2320,7 +2273,7 @@ class KeywordFinder:
2320
2273
  DiagnosticsEntry(
2321
2274
  self._create_multiple_keywords_found_message(name, found),
2322
2275
  DiagnosticSeverity.ERROR,
2323
- Error.KEYWORD_ERROR,
2276
+ Error.MULTIPLE_KEYWORDS,
2324
2277
  )
2325
2278
  )
2326
2279
  raise CancelSearchError
@@ -2342,7 +2295,7 @@ class KeywordFinder:
2342
2295
  DiagnosticsEntry(
2343
2296
  self._create_custom_and_standard_keyword_conflict_warning_message(custom, standard),
2344
2297
  DiagnosticSeverity.WARNING,
2345
- Error.KEYWORD_ERROR,
2298
+ Error.CONFLICTING_LIBRARY_KEYWORDS,
2346
2299
  )
2347
2300
  )
2348
2301
 
@@ -117,14 +117,12 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
117
117
  model: ast.AST,
118
118
  namespace: Namespace,
119
119
  finder: KeywordFinder,
120
- ignored_lines: List[int],
121
120
  ) -> None:
122
121
  super().__init__()
123
122
 
124
123
  self.model = model
125
124
  self.namespace = namespace
126
125
  self.finder = finder
127
- self._ignored_lines = ignored_lines
128
126
 
129
127
  self.current_testcase_or_keyword_name: Optional[str] = None
130
128
  self.test_template: Optional[TestTemplate] = None
@@ -261,8 +259,6 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
261
259
  )
262
260
  )
263
261
  )
264
- # r.start.character = 0
265
- # r.end.character = 0
266
262
 
267
263
  var_def = self.namespace.find_variable(
268
264
  name,
@@ -450,15 +446,6 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
450
446
  finally:
451
447
  self.node_stack = self.node_stack[:-1]
452
448
 
453
- def _should_ignore(self, range: Range) -> bool:
454
- import builtins
455
-
456
- for line_no in builtins.range(range.start.line, range.end.line + 1):
457
- if line_no in self._ignored_lines:
458
- return True
459
-
460
- return False
461
-
462
449
  def append_diagnostics(
463
450
  self,
464
451
  range: Range,
@@ -471,8 +458,6 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
471
458
  related_information: Optional[List[DiagnosticRelatedInformation]] = None,
472
459
  data: Optional[Any] = None,
473
460
  ) -> None:
474
- if self._should_ignore(range):
475
- return
476
461
 
477
462
  self._diagnostics.append(
478
463
  Diagnostic(
@@ -1167,7 +1152,7 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
1167
1152
  for v in entries.values():
1168
1153
  if v.import_source == self.namespace.source and v.import_range == range_from_token(name_token):
1169
1154
  for k in self._namespace_references:
1170
- if type(k) == type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1155
+ if type(k) is type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1171
1156
  self._namespace_references[k].add(
1172
1157
  Location(self.namespace.document.document_uri, v.import_range)
1173
1158
  )
@@ -1192,7 +1177,7 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
1192
1177
  for v in entries.values():
1193
1178
  if v.import_source == self.namespace.source and v.import_range == range_from_token(name_token):
1194
1179
  for k in self._namespace_references:
1195
- if type(k) == type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1180
+ if type(k) is type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1196
1181
  self._namespace_references[k].add(
1197
1182
  Location(self.namespace.document.document_uri, v.import_range)
1198
1183
  )
@@ -1217,7 +1202,7 @@ class NamespaceAnalyzer(Visitor, ModelHelper):
1217
1202
  for v in entries.values():
1218
1203
  if v.import_source == self.namespace.source and v.import_range == range_from_token(name_token):
1219
1204
  for k in self._namespace_references:
1220
- if type(k) == type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1205
+ if type(k) is type(v) and k.library_doc.source_or_origin == v.library_doc.source_or_origin:
1221
1206
  self._namespace_references[k].add(
1222
1207
  Location(self.namespace.document.document_uri, v.import_range)
1223
1208
  )
@@ -129,10 +129,10 @@ def range_from_node(
129
129
  return Range(start=first_range.start, end=last_range.end)
130
130
 
131
131
  return Range(
132
- start=Position(line=node.lineno - 1, character=node.col_offset),
132
+ start=Position(line=node.lineno - 1, character=node.col_offset), # type: ignore
133
133
  end=Position(
134
- line=node.end_lineno - 1 if node.end_lineno is not None else -1,
135
- character=node.end_col_offset if node.end_col_offset is not None else -1,
134
+ line=node.end_lineno - 1 if node.end_lineno is not None else -1, # type: ignore
135
+ character=node.end_col_offset if node.end_col_offset is not None else -1, # type: ignore
136
136
  ),
137
137
  )
138
138
 
@@ -1,9 +1,12 @@
1
1
  from functools import lru_cache
2
2
 
3
+ _transform_table = str.maketrans("", "", "_ ")
4
+
3
5
 
4
6
  @lru_cache(maxsize=5000)
5
7
  def normalize(text: str) -> str:
6
- return text.lower().replace("_", "").replace(" ", "")
8
+ # return text.lower().replace("_", "").replace(" ", "")
9
+ return text.casefold().translate(_transform_table)
7
10
 
8
11
 
9
12
  @lru_cache(maxsize=5000)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: robotcode-robot
3
- Version: 0.83.2
3
+ Version: 0.84.0
4
4
  Summary: Support classes for RobotCode for handling Robot Framework projects.
5
5
  Project-URL: Homepage, https://robotcode.io
6
6
  Project-URL: Donate, https://opencollective.com/robotcode
@@ -26,7 +26,7 @@ Classifier: Topic :: Utilities
26
26
  Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.8
28
28
  Requires-Dist: platformdirs<4.2.0,>=3.2.0
29
- Requires-Dist: robotcode-core==0.83.2
29
+ Requires-Dist: robotcode-core==0.84.0
30
30
  Requires-Dist: robotframework>=4.1.0
31
31
  Requires-Dist: tomli>=1.1.0; python_version < '3.11'
32
32
  Description-Content-Type: text/markdown
@@ -1,29 +1,30 @@
1
1
  robotcode/robot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- robotcode/robot/__version__.py,sha256=BysijwUtRGyTEaFK1XP_-VQUzLcWjUdfiT4EBdErGhs,23
2
+ robotcode/robot/__version__.py,sha256=KIiYae8LGfAm2z2vAqeoEPgeYngLtYMZnQCGOUKk3Nk,23
3
3
  robotcode/robot/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
4
4
  robotcode/robot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  robotcode/robot/config/loader.py,sha256=LpGqJAdysvVSZpccW-Il52xn9RMBBb9X94emlBY7zCc,6077
6
- robotcode/robot/config/model.py,sha256=yD1jaZoT5oK43bVmeIZK75vrDJRYXru8rtuxrTlxXNA,88392
6
+ robotcode/robot/config/model.py,sha256=AZFvuMCUuws5EbvX_Bk-b96tiKnIqm7REU_wO1RLJFM,88462
7
7
  robotcode/robot/config/utils.py,sha256=c_WZg39DJgM6kXcAH_h-v68qhf1eStJ0TslTawaJoZw,2827
8
8
  robotcode/robot/diagnostics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- robotcode/robot/diagnostics/document_cache_helper.py,sha256=XLOqPl88Rbo_01pt8Zx2jMH38m5kvoOnASNDoe8BK_0,22292
10
- robotcode/robot/diagnostics/entities.py,sha256=CrjhLHHwKCCE3YI_dcjoZADJz1urm0VGbGFdHXOuaoc,11110
11
- robotcode/robot/diagnostics/errors.py,sha256=VavgWYuHoW5sTT16j2rl9hxMhWxBKNSFsNmHWPzARQQ,1413
9
+ robotcode/robot/diagnostics/diagnostics_modifier.py,sha256=9AFptQsdw_TvgBkKqutpvI8WKsOUXipXQDOExarJJy4,6903
10
+ robotcode/robot/diagnostics/document_cache_helper.py,sha256=pa9AdSbEFZJ6VSdZluGyfzyZPjzBfNFAv5pXJEM-7fc,22664
11
+ robotcode/robot/diagnostics/entities.py,sha256=AtrqPAS3XUC-8VpFmqMXfMKjQHmfxXZlyGWWFaEBpQA,10979
12
+ robotcode/robot/diagnostics/errors.py,sha256=1DNxi1lbz4HAWocCi-4zY1IgUGO3J04kY_sBgYfkeX0,1520
12
13
  robotcode/robot/diagnostics/imports_manager.py,sha256=qE__lm0Hsj3R0gUauXRmbWJPYihNjk3O-c5hcICGQjc,56251
13
- robotcode/robot/diagnostics/library_doc.py,sha256=sLENYhMoq5IvYgd0jUhVpRkRTvY9IfTotlthLUUO0vY,97124
14
+ robotcode/robot/diagnostics/library_doc.py,sha256=CHgyC9GMRQFP3fGTxWa139rIcGIk8Ys6Q_ZIDSgse7k,97324
14
15
  robotcode/robot/diagnostics/model_helper.py,sha256=_5ixKKMrb-nY-uvV8_WjJ1rlNlz7gT7kHM5NYi_hjVg,30232
15
- robotcode/robot/diagnostics/namespace.py,sha256=dpaJximTWvCXvjJK1deP4SiTxxYq3r4Yid9Lf-Es8hI,91311
16
- robotcode/robot/diagnostics/namespace_analyzer.py,sha256=PWZjpLdn-9GCpp4L4dKxVF2B1hxzSEdDzBNUw2Lp51A,50937
16
+ robotcode/robot/diagnostics/namespace.py,sha256=IwWie61qd5iGMdpI285IH0jKgJWS5xRmt98lldTHxSw,89539
17
+ robotcode/robot/diagnostics/namespace_analyzer.py,sha256=G9xgJ-hPunXxfpKmZEf0xop8sIp4IhjdM3Z3C9vQU-g,50479
17
18
  robotcode/robot/diagnostics/workspace_config.py,sha256=lWNq1KmGGJ9cHFNHn0QTCBHHzgz4AewTw0l-W4TKrj0,1803
18
19
  robotcode/robot/utils/__init__.py,sha256=OjNPMn_XSnfaMCyKd8Kmq6vlRt6mIGlzW4qiiD3ykUg,447
19
- robotcode/robot/utils/ast.py,sha256=N7PobxXjpPWwv6UBa-GBn5wn6RAsiRm8unP6UZt0P6M,10193
20
+ robotcode/robot/utils/ast.py,sha256=p3S6f1mmimI47HVchGezt93jygEqs-oxKeiyqbUm0R4,10241
20
21
  robotcode/robot/utils/markdownformatter.py,sha256=IVVnCYJLpX8-sK73n3AjtjBVirB-Xa3U2ZudAtFUOD0,11621
21
- robotcode/robot/utils/match.py,sha256=jxKXVpv0SHw_LxsDc1vgOxSGGtcV_9eO9cOVj4MAgIo,527
22
+ robotcode/robot/utils/match.py,sha256=ofyfXgrvVddl7a064Dk5Kiqp3a-n_6gTIgqDbL3E80Q,632
22
23
  robotcode/robot/utils/robot_path.py,sha256=qKBh1cEnReBBLKkWu4gB9EzM-scAwE4xJc1m6v2LRN0,1786
23
24
  robotcode/robot/utils/stubs.py,sha256=6-DMI_CQVJHDgG13t-zINKGCRb_Q7MQPm0_AkfhAEvE,748
24
25
  robotcode/robot/utils/variables.py,sha256=fEl8S37lb_mD4hn2MZRAlkiuLGBjAOeZVK0r2o2CfPw,742
25
26
  robotcode/robot/utils/visitor.py,sha256=uYLqEhGPmzWKWI3SSrmCaYMwtKvNShvbiPZ4b3FavX8,3241
26
- robotcode_robot-0.83.2.dist-info/METADATA,sha256=PikDo1yffdVRYyIwizMOo4T0WPLN8SNJ2FI7K3tADU0,2240
27
- robotcode_robot-0.83.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
28
- robotcode_robot-0.83.2.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
29
- robotcode_robot-0.83.2.dist-info/RECORD,,
27
+ robotcode_robot-0.84.0.dist-info/METADATA,sha256=L3XwWzyT6nrMj9hWOPAplkITehYAVXkbDSqkT9porE8,2240
28
+ robotcode_robot-0.84.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
29
+ robotcode_robot-0.84.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
30
+ robotcode_robot-0.84.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.24.2
2
+ Generator: hatchling 1.25.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any