robotcode-robot 0.93.0__py3-none-any.whl → 0.94.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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 +79 -37
- robotcode/robot/diagnostics/keyword_finder.py +458 -0
- robotcode/robot/diagnostics/library_doc.py +37 -19
- 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.0.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.0.dist-info/RECORD +0 -30
- {robotcode_robot-0.93.0.dist-info → robotcode_robot-0.94.0.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.93.0.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,
|
@@ -1579,6 +1619,7 @@ class ImportsManager:
|
|
1579
1619
|
scalar: str,
|
1580
1620
|
base_dir: str = ".",
|
1581
1621
|
variables: Optional[Dict[str, Any]] = None,
|
1622
|
+
ignore_errors: bool = False,
|
1582
1623
|
) -> Any:
|
1583
1624
|
return replace_variables_scalar(
|
1584
1625
|
scalar,
|
@@ -1586,4 +1627,5 @@ class ImportsManager:
|
|
1586
1627
|
base_dir,
|
1587
1628
|
self.get_resolvable_command_line_variables(),
|
1588
1629
|
variables,
|
1630
|
+
ignore_errors=ignore_errors,
|
1589
1631
|
)
|