robotcode-robot 0.93.1__py3-none-any.whl → 0.94.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.
- robotcode/robot/__version__.py +1 -1
- robotcode/robot/diagnostics/document_cache_helper.py +11 -6
- robotcode/robot/diagnostics/entities.py +2 -2
- robotcode/robot/diagnostics/errors.py +6 -1
- robotcode/robot/diagnostics/imports_manager.py +77 -37
- robotcode/robot/diagnostics/keyword_finder.py +458 -0
- robotcode/robot/diagnostics/library_doc.py +20 -14
- robotcode/robot/diagnostics/model_helper.py +42 -27
- robotcode/robot/diagnostics/namespace.py +142 -552
- robotcode/robot/diagnostics/namespace_analyzer.py +952 -462
- robotcode/robot/utils/markdownformatter.py +8 -11
- robotcode/robot/utils/visitor.py +7 -13
- {robotcode_robot-0.93.1.dist-info → robotcode_robot-0.94.0.dist-info}/METADATA +2 -2
- robotcode_robot-0.94.0.dist-info/RECORD +31 -0
- robotcode_robot-0.93.1.dist-info/RECORD +0 -30
- {robotcode_robot-0.93.1.dist-info → robotcode_robot-0.94.0.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.93.1.dist-info → robotcode_robot-0.94.0.dist-info}/licenses/LICENSE.txt +0 -0
robotcode/robot/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.
|
1
|
+
__version__ = "0.94.0"
|
@@ -118,8 +118,7 @@ class DocumentsCacheHelper:
|
|
118
118
|
except ValueError as e:
|
119
119
|
ex = e
|
120
120
|
self._logger.exception(
|
121
|
-
lambda: f"Language configuration is not valid: {ex}"
|
122
|
-
"\nPlease check your 'robotcode.robot.language' configuration.",
|
121
|
+
lambda: f"Language configuration is not valid: {ex}",
|
123
122
|
exc_info=ex,
|
124
123
|
level=CRITICAL,
|
125
124
|
)
|
@@ -410,7 +409,16 @@ class DocumentsCacheHelper:
|
|
410
409
|
return document.get_cache(self.__get_namespace)
|
411
410
|
|
412
411
|
def __get_namespace(self, document: TextDocument) -> Namespace:
|
413
|
-
|
412
|
+
document_type = self.get_document_type(document)
|
413
|
+
|
414
|
+
if document_type == DocumentType.INIT:
|
415
|
+
return self.get_init_namespace(document)
|
416
|
+
if document_type == DocumentType.RESOURCE:
|
417
|
+
return self.get_resource_namespace(document)
|
418
|
+
if document_type == DocumentType.GENERAL:
|
419
|
+
return self.get_general_namespace(document)
|
420
|
+
|
421
|
+
return self.__get_namespace_for_document_type(document, document_type)
|
414
422
|
|
415
423
|
def get_resource_namespace(self, document: TextDocument) -> Namespace:
|
416
424
|
return document.get_cache(self.__get_resource_namespace)
|
@@ -448,9 +456,6 @@ class DocumentsCacheHelper:
|
|
448
456
|
|
449
457
|
def __namespace_initialized(self, sender: Namespace) -> None:
|
450
458
|
if sender.document is not None:
|
451
|
-
self._logger.debug(
|
452
|
-
lambda: f"Save initialized Namespace: {sender.document.uri if sender.document else None}"
|
453
|
-
)
|
454
459
|
sender.document.set_data(self.INITIALIZED_NAMESPACE, sender)
|
455
460
|
self.namespace_initialized(self, sender)
|
456
461
|
|
@@ -246,7 +246,7 @@ class GlobalVariableDefinition(VariableDefinition):
|
|
246
246
|
|
247
247
|
|
248
248
|
@dataclass
|
249
|
-
class BuiltInVariableDefinition(
|
249
|
+
class BuiltInVariableDefinition(GlobalVariableDefinition):
|
250
250
|
type: VariableDefinitionType = VariableDefinitionType.BUILTIN_VARIABLE
|
251
251
|
resolvable: bool = True
|
252
252
|
|
@@ -266,7 +266,7 @@ class CommandLineVariableDefinition(GlobalVariableDefinition):
|
|
266
266
|
|
267
267
|
|
268
268
|
@dataclass
|
269
|
-
class ArgumentDefinition(
|
269
|
+
class ArgumentDefinition(LocalVariableDefinition):
|
270
270
|
type: VariableDefinitionType = VariableDefinitionType.ARGUMENT
|
271
271
|
keyword_doc: Optional["KeywordDoc"] = field(default=None, compare=False, metadata={"nosave": True})
|
272
272
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
from typing import final
|
2
2
|
|
3
|
-
DIAGNOSTICS_SOURCE_NAME = "robotcode
|
3
|
+
DIAGNOSTICS_SOURCE_NAME = "robotcode"
|
4
4
|
|
5
5
|
|
6
6
|
@final
|
@@ -35,3 +35,8 @@ class Error:
|
|
35
35
|
CONFLICTING_LIBRARY_KEYWORDS = "ConflictingLibraryKeywords"
|
36
36
|
INVALID_HEADER = "InvalidHeader"
|
37
37
|
DEPRECATED_HEADER = "DeprecatedHeader"
|
38
|
+
OVERRIDDEN_BY_COMMANDLINE = "OverriddenByCommandLine"
|
39
|
+
VARIABLE_ALREADY_DEFINED = "VariableAlreadyDefined"
|
40
|
+
VARIABLE_OVERRIDDEN = "VariableOverridden"
|
41
|
+
MODEL_ERROR = "ModelError"
|
42
|
+
TOKEN_ERROR = "TokenError"
|
@@ -9,7 +9,7 @@ import weakref
|
|
9
9
|
import zlib
|
10
10
|
from abc import ABC, abstractmethod
|
11
11
|
from collections import OrderedDict
|
12
|
-
from concurrent.futures import ProcessPoolExecutor
|
12
|
+
from concurrent.futures import ProcessPoolExecutor, TimeoutError
|
13
13
|
from dataclasses import dataclass
|
14
14
|
from pathlib import Path
|
15
15
|
from typing import (
|
@@ -25,6 +25,7 @@ from typing import (
|
|
25
25
|
final,
|
26
26
|
)
|
27
27
|
|
28
|
+
from robot.utils.text import split_args_from_name_or_path
|
28
29
|
from robotcode.core.concurrent import RLock, run_as_task
|
29
30
|
from robotcode.core.documents_manager import DocumentsManager
|
30
31
|
from robotcode.core.event import event
|
@@ -82,9 +83,8 @@ RESOURCE_EXTENSIONS = (
|
|
82
83
|
REST_EXTENSIONS = (".rst", ".rest")
|
83
84
|
|
84
85
|
|
85
|
-
LOAD_LIBRARY_TIME_OUT =
|
86
|
-
|
87
|
-
COMPLETE_LIBRARY_IMPORT_TIME_OUT = COMPLETE_RESOURCE_IMPORT_TIME_OUT = COMPLETE_VARIABLES_IMPORT_TIME_OUT = 10
|
86
|
+
LOAD_LIBRARY_TIME_OUT = 10
|
87
|
+
COMPLETE_LIBRARY_IMPORT_TIME_OUT = COMPLETE_RESOURCE_IMPORT_TIME_OUT = COMPLETE_VARIABLES_IMPORT_TIME_OUT = 5
|
88
88
|
|
89
89
|
|
90
90
|
class _EntryKey:
|
@@ -578,6 +578,10 @@ class ImportsManager:
|
|
578
578
|
self._resource_document_changed_timer_interval = 1
|
579
579
|
self._resource_document_changed_documents: Set[TextDocument] = set()
|
580
580
|
|
581
|
+
self._resource_libdoc_cache: "weakref.WeakKeyDictionary[ast.AST, Dict[Tuple[str, bool], LibraryDoc]]" = (
|
582
|
+
weakref.WeakKeyDictionary()
|
583
|
+
)
|
584
|
+
|
581
585
|
def __del__(self) -> None:
|
582
586
|
try:
|
583
587
|
if self._executor is not None:
|
@@ -599,8 +603,6 @@ class ImportsManager:
|
|
599
603
|
|
600
604
|
@_logger.call
|
601
605
|
def get_command_line_variables(self) -> List[VariableDefinition]:
|
602
|
-
from robot.utils.text import split_args_from_name_or_path
|
603
|
-
|
604
606
|
with self._command_line_variables_lock:
|
605
607
|
if self._command_line_variables is None:
|
606
608
|
command_line_vars: List[VariableDefinition] = []
|
@@ -659,7 +661,11 @@ class ImportsManager:
|
|
659
661
|
raise
|
660
662
|
except BaseException as e:
|
661
663
|
# TODO add diagnostics
|
662
|
-
|
664
|
+
ex = e
|
665
|
+
self._logger.exception(
|
666
|
+
lambda: f"Error getting command line variables: {ex}",
|
667
|
+
exc_info=ex,
|
668
|
+
)
|
663
669
|
|
664
670
|
self._command_line_variables = command_line_vars
|
665
671
|
|
@@ -854,7 +860,7 @@ class ImportsManager:
|
|
854
860
|
) -> None:
|
855
861
|
try:
|
856
862
|
if len(entry.references) == 0 or now:
|
857
|
-
self._logger.debug(lambda: f"Remove
|
863
|
+
self._logger.debug(lambda: f"Remove Variables Entry {entry_key}")
|
858
864
|
with self._variables_lock:
|
859
865
|
if len(entry.references) == 0:
|
860
866
|
e1 = self._variables.get(entry_key, None)
|
@@ -1148,6 +1154,7 @@ class ImportsManager:
|
|
1148
1154
|
meta, _source, ignore_arguments = self.get_library_meta(name, base_dir, variables)
|
1149
1155
|
|
1150
1156
|
if meta is not None and not meta.has_errors:
|
1157
|
+
|
1151
1158
|
meta_file = Path(self.lib_doc_cache_path, meta.filepath_base + ".meta.json")
|
1152
1159
|
if meta_file.exists():
|
1153
1160
|
try:
|
@@ -1157,7 +1164,8 @@ class ImportsManager:
|
|
1157
1164
|
if saved_meta.has_errors:
|
1158
1165
|
self._logger.debug(
|
1159
1166
|
lambda: "Saved library spec for {name}{args!r} is not used "
|
1160
|
-
"due to errors in meta data"
|
1167
|
+
"due to errors in meta data",
|
1168
|
+
context_name="import",
|
1161
1169
|
)
|
1162
1170
|
|
1163
1171
|
if not saved_meta.has_errors and saved_meta == meta:
|
@@ -1165,6 +1173,10 @@ class ImportsManager:
|
|
1165
1173
|
self.lib_doc_cache_path,
|
1166
1174
|
meta.filepath_base + ".spec.json",
|
1167
1175
|
)
|
1176
|
+
|
1177
|
+
self._logger.debug(
|
1178
|
+
lambda: f"Use cached library meta data for {name}", context_name="import"
|
1179
|
+
)
|
1168
1180
|
return from_json(spec_path.read_text("utf-8"), LibraryDoc)
|
1169
1181
|
|
1170
1182
|
except (SystemExit, KeyboardInterrupt):
|
@@ -1178,17 +1190,22 @@ class ImportsManager:
|
|
1178
1190
|
except BaseException as e:
|
1179
1191
|
self._logger.exception(e)
|
1180
1192
|
|
1193
|
+
self._logger.debug(lambda: f"Load library in process {name}{args!r}", context_name="import")
|
1181
1194
|
executor = ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn"))
|
1182
1195
|
try:
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1196
|
+
try:
|
1197
|
+
result = executor.submit(
|
1198
|
+
get_library_doc,
|
1199
|
+
name,
|
1200
|
+
args if not ignore_arguments else (),
|
1201
|
+
working_dir,
|
1202
|
+
base_dir,
|
1203
|
+
self.get_resolvable_command_line_variables(),
|
1204
|
+
variables,
|
1205
|
+
).result(LOAD_LIBRARY_TIME_OUT)
|
1206
|
+
|
1207
|
+
except TimeoutError as e:
|
1208
|
+
raise RuntimeError(f"Timeout loading library {name}({args!r})") from e
|
1192
1209
|
|
1193
1210
|
except (SystemExit, KeyboardInterrupt):
|
1194
1211
|
raise
|
@@ -1273,17 +1290,29 @@ class ImportsManager:
|
|
1273
1290
|
self,
|
1274
1291
|
model: ast.AST,
|
1275
1292
|
source: str,
|
1276
|
-
model_type: str = "RESOURCE",
|
1277
|
-
scope: str = "GLOBAL",
|
1278
1293
|
append_model_errors: bool = True,
|
1279
1294
|
) -> LibraryDoc:
|
1280
|
-
|
1295
|
+
key = (source, append_model_errors)
|
1296
|
+
|
1297
|
+
entry = None
|
1298
|
+
if model in self._resource_libdoc_cache:
|
1299
|
+
entry = self._resource_libdoc_cache.get(model, None)
|
1300
|
+
|
1301
|
+
if entry and key in entry:
|
1302
|
+
return entry[key]
|
1303
|
+
|
1304
|
+
result = get_model_doc(
|
1281
1305
|
model=model,
|
1282
1306
|
source=source,
|
1283
|
-
model_type=model_type,
|
1284
|
-
scope=scope,
|
1285
1307
|
append_model_errors=append_model_errors,
|
1286
1308
|
)
|
1309
|
+
if entry is None:
|
1310
|
+
entry = {}
|
1311
|
+
self._resource_libdoc_cache[model] = entry
|
1312
|
+
|
1313
|
+
entry[key] = result
|
1314
|
+
|
1315
|
+
return result
|
1287
1316
|
|
1288
1317
|
def _get_variables_libdoc_handler(
|
1289
1318
|
self,
|
@@ -1350,15 +1379,20 @@ class ImportsManager:
|
|
1350
1379
|
|
1351
1380
|
executor = ProcessPoolExecutor(max_workers=1, mp_context=mp.get_context("spawn"))
|
1352
1381
|
try:
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1382
|
+
try:
|
1383
|
+
result = executor.submit(
|
1384
|
+
get_variables_doc,
|
1385
|
+
name,
|
1386
|
+
args,
|
1387
|
+
working_dir,
|
1388
|
+
base_dir,
|
1389
|
+
self.get_resolvable_command_line_variables() if resolve_command_line_vars else None,
|
1390
|
+
variables,
|
1391
|
+
).result(LOAD_LIBRARY_TIME_OUT)
|
1392
|
+
|
1393
|
+
except TimeoutError as e:
|
1394
|
+
raise RuntimeError(f"Timeout loading library {name}({args!r})") from e
|
1395
|
+
|
1362
1396
|
except (SystemExit, KeyboardInterrupt):
|
1363
1397
|
raise
|
1364
1398
|
except BaseException as e:
|
@@ -1489,9 +1523,15 @@ class ImportsManager:
|
|
1489
1523
|
variables: Optional[Dict[str, Any]] = None,
|
1490
1524
|
) -> Tuple["Namespace", LibraryDoc]:
|
1491
1525
|
with self._logger.measure_time(lambda: f"getting namespace and libdoc for {name}", context_name="import"):
|
1492
|
-
|
1526
|
+
with self._logger.measure_time(lambda: f"getting resource entry {name}", context_name="import"):
|
1527
|
+
entry = self._get_entry_for_resource_import(name, base_dir, sentinel, variables)
|
1528
|
+
|
1529
|
+
with self._logger.measure_time(lambda: f"getting namespace {name}", context_name="import"):
|
1530
|
+
namespace = entry.get_namespace()
|
1531
|
+
with self._logger.measure_time(lambda: f"getting libdoc {name}", context_name="import"):
|
1532
|
+
libdoc = entry.get_libdoc()
|
1493
1533
|
|
1494
|
-
return
|
1534
|
+
return namespace, libdoc
|
1495
1535
|
|
1496
1536
|
def get_namespace_for_resource_import(
|
1497
1537
|
self,
|
@@ -1528,7 +1568,7 @@ class ImportsManager:
|
|
1528
1568
|
base_dir,
|
1529
1569
|
self.get_resolvable_command_line_variables(),
|
1530
1570
|
variables,
|
1531
|
-
).result(
|
1571
|
+
).result(COMPLETE_LIBRARY_IMPORT_TIME_OUT)
|
1532
1572
|
|
1533
1573
|
def complete_resource_import(
|
1534
1574
|
self,
|
@@ -1543,7 +1583,7 @@ class ImportsManager:
|
|
1543
1583
|
base_dir,
|
1544
1584
|
self.get_resolvable_command_line_variables(),
|
1545
1585
|
variables,
|
1546
|
-
).result(
|
1586
|
+
).result(COMPLETE_RESOURCE_IMPORT_TIME_OUT)
|
1547
1587
|
|
1548
1588
|
def complete_variables_import(
|
1549
1589
|
self,
|
@@ -1558,7 +1598,7 @@ class ImportsManager:
|
|
1558
1598
|
base_dir,
|
1559
1599
|
self.get_resolvable_command_line_variables(),
|
1560
1600
|
variables,
|
1561
|
-
).result(
|
1601
|
+
).result(COMPLETE_VARIABLES_IMPORT_TIME_OUT)
|
1562
1602
|
|
1563
1603
|
def resolve_variable(
|
1564
1604
|
self,
|