robotcode-robot 0.68.0__py3-none-any.whl → 0.68.2__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.
@@ -0,0 +1,377 @@
1
+ from dataclasses import dataclass, field
2
+ from enum import Enum
3
+ from typing import (
4
+ TYPE_CHECKING,
5
+ Any,
6
+ Callable,
7
+ List,
8
+ Optional,
9
+ Tuple,
10
+ TypeVar,
11
+ cast,
12
+ )
13
+
14
+ from robot.parsing.lexer.tokens import Token
15
+ from robotcode.core.lsp.types import Position, Range
16
+ from robotcode.robot.utils.ast import range_from_token
17
+
18
+ if TYPE_CHECKING:
19
+ from robotcode.robot.diagnostics.library_doc import KeywordDoc, LibraryDoc
20
+
21
+ _F = TypeVar("_F", bound=Callable[..., Any])
22
+
23
+
24
+ _NOT_SET = object()
25
+
26
+
27
+ def single_call(func: _F) -> _F:
28
+ name = f"__single_result_{func.__name__}__"
29
+
30
+ def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
31
+ result = self.__dict__.get(name, _NOT_SET)
32
+ if result is _NOT_SET:
33
+ result = func(self, *args, **kwargs)
34
+ self.__dict__[name] = result
35
+ return result
36
+
37
+ return cast(_F, wrapper)
38
+
39
+
40
+ @dataclass
41
+ class SourceEntity:
42
+ line_no: int
43
+ col_offset: int
44
+ end_line_no: int
45
+ end_col_offset: int
46
+ source: Optional[str]
47
+
48
+ @property
49
+ def range(self) -> Range:
50
+ return Range(
51
+ start=Position(line=self.line_no - 1, character=self.col_offset),
52
+ end=Position(line=self.end_line_no - 1, character=self.end_col_offset),
53
+ )
54
+
55
+ @single_call
56
+ def __hash__(self) -> int:
57
+ return hash(
58
+ (
59
+ self.line_no,
60
+ self.col_offset,
61
+ self.end_line_no,
62
+ self.end_col_offset,
63
+ self.source,
64
+ )
65
+ )
66
+
67
+
68
+ @dataclass
69
+ class Import(SourceEntity):
70
+ name: Optional[str]
71
+ name_token: Optional[Token]
72
+
73
+ @property
74
+ def range(self) -> Range:
75
+ return Range(
76
+ start=Position(
77
+ line=self.name_token.lineno - 1 if self.name_token is not None else self.line_no - 1,
78
+ character=self.name_token.col_offset if self.name_token is not None else self.col_offset,
79
+ ),
80
+ end=Position(
81
+ line=self.name_token.lineno - 1 if self.name_token is not None else self.end_line_no - 1,
82
+ character=self.name_token.end_col_offset if self.name_token is not None else self.end_col_offset,
83
+ ),
84
+ )
85
+
86
+
87
+ @dataclass
88
+ class LibraryImport(Import):
89
+ args: Tuple[str, ...] = ()
90
+ alias: Optional[str] = None
91
+ alias_token: Optional[Token] = None
92
+
93
+ @property
94
+ def alias_range(self) -> Range:
95
+ return Range(
96
+ start=Position(
97
+ line=self.alias_token.lineno - 1 if self.alias_token is not None else -1,
98
+ character=self.alias_token.col_offset if self.alias_token is not None else -1,
99
+ ),
100
+ end=Position(
101
+ line=self.alias_token.lineno - 1 if self.alias_token is not None else -1,
102
+ character=self.alias_token.end_col_offset if self.alias_token is not None else -1,
103
+ ),
104
+ )
105
+
106
+ @single_call
107
+ def __hash__(self) -> int:
108
+ return hash((type(self), self.name, self.args, self.alias))
109
+
110
+
111
+ @dataclass
112
+ class ResourceImport(Import):
113
+ @single_call
114
+ def __hash__(self) -> int:
115
+ return hash((type(self), self.name))
116
+
117
+
118
+ @dataclass
119
+ class VariablesImport(Import):
120
+ args: Tuple[str, ...] = ()
121
+
122
+ @single_call
123
+ def __hash__(self) -> int:
124
+ return hash((type(self), self.name, self.args))
125
+
126
+
127
+ class InvalidVariableError(Exception):
128
+ pass
129
+
130
+
131
+ class VariableMatcher:
132
+ def __init__(self, name: str) -> None:
133
+ from robot.variables.search import search_variable
134
+ from robotcode.robot.utils.match import normalize
135
+
136
+ self.name = name
137
+
138
+ match = search_variable(name, "$@&%", ignore_errors=True)
139
+
140
+ if match.base is None:
141
+ raise InvalidVariableError(f"Invalid variable '{name}'")
142
+
143
+ self.base = match.base
144
+
145
+ self.normalized_name = str(normalize(self.base))
146
+
147
+ def __eq__(self, o: object) -> bool:
148
+ from robot.utils.normalizing import normalize
149
+ from robot.variables.search import search_variable
150
+
151
+ if isinstance(o, VariableMatcher):
152
+ return o.normalized_name == self.normalized_name
153
+
154
+ if isinstance(o, str):
155
+ match = search_variable(o, "$@&%", ignore_errors=True)
156
+ base = match.base
157
+ normalized = str(normalize(base))
158
+ return self.normalized_name == normalized
159
+
160
+ return False
161
+
162
+ def __hash__(self) -> int:
163
+ return hash(self.name)
164
+
165
+ def __str__(self) -> str:
166
+ return self.name
167
+
168
+ def __repr__(self) -> str:
169
+ return f"{type(self).__name__}(name={self.name!r})"
170
+
171
+
172
+ class VariableDefinitionType(Enum):
173
+ VARIABLE = "suite variable"
174
+ LOCAL_VARIABLE = "local variable"
175
+ ARGUMENT = "argument"
176
+ COMMAND_LINE_VARIABLE = "global variable [command line]"
177
+ BUILTIN_VARIABLE = "builtin variable"
178
+ IMPORTED_VARIABLE = "suite variable [imported]"
179
+ ENVIRONMENT_VARIABLE = "environment variable"
180
+ VARIABLE_NOT_FOUND = "variable not found"
181
+
182
+
183
+ @dataclass
184
+ class VariableDefinition(SourceEntity):
185
+ name: str
186
+ name_token: Optional[Token]
187
+ type: VariableDefinitionType = VariableDefinitionType.VARIABLE
188
+
189
+ has_value: bool = field(default=False, compare=False)
190
+ resolvable: bool = field(default=False, compare=False)
191
+
192
+ value: Any = field(default=None, compare=False)
193
+ value_is_native: bool = field(default=False, compare=False)
194
+
195
+ @property
196
+ def matcher(self) -> VariableMatcher:
197
+ if not hasattr(self, "__matcher"):
198
+ self.__matcher = VariableMatcher(self.name)
199
+ return self.__matcher
200
+
201
+ @single_call
202
+ def __hash__(self) -> int:
203
+ return hash((type(self), self.name, self.type, self.range, self.source))
204
+
205
+ @property
206
+ def name_range(self) -> Range:
207
+ if self.name_token is not None:
208
+ return range_from_token(self.name_token)
209
+
210
+ return self.range
211
+
212
+ @property
213
+ def range(self) -> Range:
214
+ return Range(
215
+ start=Position(line=self.line_no - 1, character=self.col_offset),
216
+ end=Position(line=self.end_line_no - 1, character=self.end_col_offset),
217
+ )
218
+
219
+
220
+ @dataclass
221
+ class LocalVariableDefinition(VariableDefinition):
222
+ type: VariableDefinitionType = VariableDefinitionType.LOCAL_VARIABLE
223
+
224
+ @single_call
225
+ def __hash__(self) -> int:
226
+ return hash((type(self), self.name, self.type, self.range, self.source))
227
+
228
+
229
+ @dataclass
230
+ class BuiltInVariableDefinition(VariableDefinition):
231
+ type: VariableDefinitionType = VariableDefinitionType.BUILTIN_VARIABLE
232
+ resolvable: bool = True
233
+
234
+ @single_call
235
+ def __hash__(self) -> int:
236
+ return hash((type(self), self.name, self.type))
237
+
238
+
239
+ @dataclass
240
+ class CommandLineVariableDefinition(VariableDefinition):
241
+ type: VariableDefinitionType = VariableDefinitionType.COMMAND_LINE_VARIABLE
242
+ resolvable: bool = True
243
+
244
+ @single_call
245
+ def __hash__(self) -> int:
246
+ return hash((type(self), self.name, self.type))
247
+
248
+
249
+ @dataclass
250
+ class ArgumentDefinition(VariableDefinition):
251
+ type: VariableDefinitionType = VariableDefinitionType.ARGUMENT
252
+ keyword_doc: Optional["KeywordDoc"] = field(default=None, compare=False, metadata={"nosave": True})
253
+
254
+ @single_call
255
+ def __hash__(self) -> int:
256
+ return hash((type(self), self.name, self.type, self.range, self.source))
257
+
258
+
259
+ @dataclass
260
+ class LibraryArgumentDefinition(ArgumentDefinition):
261
+ @single_call
262
+ def __hash__(self) -> int:
263
+ return hash((type(self), self.name, self.type, self.range, self.source))
264
+
265
+
266
+ @dataclass(frozen=True, eq=False, repr=False)
267
+ class NativeValue:
268
+ value: Any
269
+
270
+ def __repr__(self) -> str:
271
+ return repr(self.value)
272
+
273
+ def __str__(self) -> str:
274
+ return str(self.value)
275
+
276
+
277
+ @dataclass
278
+ class ImportedVariableDefinition(VariableDefinition):
279
+ type: VariableDefinitionType = VariableDefinitionType.IMPORTED_VARIABLE
280
+ value: Optional[NativeValue] = field(default=None, compare=False)
281
+
282
+ @single_call
283
+ def __hash__(self) -> int:
284
+ return hash((type(self), self.name, self.type, self.source))
285
+
286
+
287
+ @dataclass
288
+ class EnvironmentVariableDefinition(VariableDefinition):
289
+ type: VariableDefinitionType = VariableDefinitionType.ENVIRONMENT_VARIABLE
290
+ resolvable: bool = True
291
+
292
+ default_value: Any = field(default=None, compare=False)
293
+
294
+ @single_call
295
+ def __hash__(self) -> int:
296
+ return hash((type(self), self.name, self.type))
297
+
298
+
299
+ @dataclass
300
+ class VariableNotFoundDefinition(VariableDefinition):
301
+ type: VariableDefinitionType = VariableDefinitionType.VARIABLE_NOT_FOUND
302
+ resolvable: bool = False
303
+
304
+ @single_call
305
+ def __hash__(self) -> int:
306
+ return hash((type(self), self.name, self.type))
307
+
308
+
309
+ @dataclass
310
+ class LibraryEntry:
311
+ name: str
312
+ import_name: str
313
+ library_doc: "LibraryDoc" = field(compare=False)
314
+ args: Tuple[Any, ...] = ()
315
+ alias: Optional[str] = None
316
+ import_range: Range = field(default_factory=Range.zero)
317
+ import_source: Optional[str] = None
318
+ alias_range: Range = field(default_factory=Range.zero)
319
+
320
+ def __str__(self) -> str:
321
+ result = self.import_name
322
+ if self.args:
323
+ result += f" {self.args!s}"
324
+ if self.alias:
325
+ result += f" WITH NAME {self.alias}"
326
+ return result
327
+
328
+ @single_call
329
+ def __hash__(self) -> int:
330
+ return hash(
331
+ (
332
+ type(self),
333
+ self.name,
334
+ self.import_name,
335
+ self.args,
336
+ self.alias,
337
+ self.import_range,
338
+ self.import_source,
339
+ self.alias_range,
340
+ )
341
+ )
342
+
343
+
344
+ @dataclass
345
+ class ResourceEntry(LibraryEntry):
346
+ imports: List[Import] = field(default_factory=list, compare=False)
347
+ variables: List[VariableDefinition] = field(default_factory=list, compare=False)
348
+
349
+ @single_call
350
+ def __hash__(self) -> int:
351
+ return hash(
352
+ (
353
+ type(self),
354
+ self.name,
355
+ self.import_name,
356
+ self.import_range,
357
+ self.import_source,
358
+ )
359
+ )
360
+
361
+
362
+ @dataclass
363
+ class VariablesEntry(LibraryEntry):
364
+ variables: List[ImportedVariableDefinition] = field(default_factory=list, compare=False)
365
+
366
+ @single_call
367
+ def __hash__(self) -> int:
368
+ return hash(
369
+ (
370
+ type(self),
371
+ self.name,
372
+ self.import_name,
373
+ self.args,
374
+ self.import_range,
375
+ self.import_source,
376
+ )
377
+ )