robotcode-robot 0.75.0__py3-none-any.whl → 0.76.1__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 +62 -4
- robotcode/robot/diagnostics/entities.py +4 -5
- robotcode/robot/diagnostics/imports_manager.py +37 -21
- robotcode/robot/diagnostics/library_doc.py +93 -108
- robotcode/robot/diagnostics/model_helper.py +1 -1
- robotcode/robot/diagnostics/namespace.py +352 -266
- robotcode/robot/diagnostics/namespace_analyzer.py +36 -6
- robotcode/robot/diagnostics/workspace_config.py +1 -0
- {robotcode_robot-0.75.0.dist-info → robotcode_robot-0.76.1.dist-info}/METADATA +2 -2
- {robotcode_robot-0.75.0.dist-info → robotcode_robot-0.76.1.dist-info}/RECORD +13 -13
- {robotcode_robot-0.75.0.dist-info → robotcode_robot-0.76.1.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.75.0.dist-info → robotcode_robot-0.76.1.dist-info}/licenses/LICENSE.txt +0 -0
@@ -584,6 +584,9 @@ class Namespace:
|
|
584
584
|
self._global_variables: Optional[List[VariableDefinition]] = None
|
585
585
|
self._global_variables_lock = RLock(default_timeout=120, name="Namespace.global_variables")
|
586
586
|
|
587
|
+
self._suite_variables: Optional[Dict[str, Any]] = None
|
588
|
+
self._suite_variables_lock = RLock(default_timeout=120, name="Namespace.global_variables")
|
589
|
+
|
587
590
|
self._diagnostics: List[Diagnostic] = []
|
588
591
|
self._keyword_references: Dict[KeywordDoc, Set[Location]] = {}
|
589
592
|
self._variable_references: Dict[VariableDefinition, Set[Location]] = {}
|
@@ -600,10 +603,10 @@ class Namespace:
|
|
600
603
|
|
601
604
|
self._finder: Optional[KeywordFinder] = None
|
602
605
|
|
603
|
-
self.imports_manager.imports_changed.add(self.
|
604
|
-
self.imports_manager.libraries_changed.add(self.
|
605
|
-
self.imports_manager.resources_changed.add(self.
|
606
|
-
self.imports_manager.variables_changed.add(self.
|
606
|
+
self.imports_manager.imports_changed.add(self._on_imports_changed)
|
607
|
+
self.imports_manager.libraries_changed.add(self._on_libraries_changed)
|
608
|
+
self.imports_manager.resources_changed.add(self._on_resources_changed)
|
609
|
+
self.imports_manager.variables_changed.add(self._on_variables_changed)
|
607
610
|
|
608
611
|
self._in_initialize = False
|
609
612
|
|
@@ -618,6 +621,15 @@ class Namespace:
|
|
618
621
|
@event
|
619
622
|
def has_analysed(sender) -> None: ...
|
620
623
|
|
624
|
+
@event
|
625
|
+
def library_import_changed(sender) -> None: ...
|
626
|
+
|
627
|
+
@event
|
628
|
+
def resource_import_changed(sender) -> None: ...
|
629
|
+
|
630
|
+
@event
|
631
|
+
def variables_import_changed(sender) -> None: ...
|
632
|
+
|
621
633
|
@property
|
622
634
|
def document(self) -> Optional[TextDocument]:
|
623
635
|
return self._document() if self._document is not None else None
|
@@ -629,12 +641,12 @@ class Namespace:
|
|
629
641
|
|
630
642
|
return self._search_order
|
631
643
|
|
632
|
-
def
|
644
|
+
def _on_imports_changed(self, sender: Any, uri: DocumentUri) -> None:
|
633
645
|
# TODO: optimise this by checking our imports
|
634
646
|
self.invalidate()
|
635
647
|
|
636
648
|
@_logger.call
|
637
|
-
def
|
649
|
+
def _on_libraries_changed(self, sender: Any, libraries: List[LibraryDoc]) -> None:
|
638
650
|
if not self.initialized or self.invalid:
|
639
651
|
return
|
640
652
|
|
@@ -649,7 +661,7 @@ class Namespace:
|
|
649
661
|
self.invalidate()
|
650
662
|
|
651
663
|
@_logger.call
|
652
|
-
def
|
664
|
+
def _on_resources_changed(self, sender: Any, resources: List[LibraryDoc]) -> None:
|
653
665
|
if not self.initialized or self.invalid:
|
654
666
|
return
|
655
667
|
|
@@ -664,7 +676,7 @@ class Namespace:
|
|
664
676
|
self.invalidate()
|
665
677
|
|
666
678
|
@_logger.call
|
667
|
-
def
|
679
|
+
def _on_variables_changed(self, sender: Any, variables: List[LibraryDoc]) -> None:
|
668
680
|
if not self.initialized or self.invalid:
|
669
681
|
return
|
670
682
|
|
@@ -684,12 +696,20 @@ class Namespace:
|
|
684
696
|
|
685
697
|
def _invalidate(self) -> None:
|
686
698
|
self._invalid = True
|
699
|
+
self.imports_manager.imports_changed.remove(self._on_imports_changed)
|
700
|
+
self.imports_manager.libraries_changed.remove(self._on_libraries_changed)
|
701
|
+
self.imports_manager.resources_changed.remove(self._on_resources_changed)
|
702
|
+
self.imports_manager.variables_changed.remove(self._on_variables_changed)
|
687
703
|
|
688
704
|
@_logger.call
|
689
|
-
def invalidate(self) ->
|
705
|
+
def invalidate(self) -> bool:
|
690
706
|
with self._initialize_lock:
|
707
|
+
if self._invalid:
|
708
|
+
return False
|
709
|
+
|
691
710
|
self._invalidate()
|
692
711
|
self.has_invalidated(self)
|
712
|
+
return True
|
693
713
|
|
694
714
|
@_logger.call
|
695
715
|
def get_diagnostics(self) -> List[Diagnostic]:
|
@@ -796,7 +816,7 @@ class Namespace:
|
|
796
816
|
|
797
817
|
imports = self.get_imports()
|
798
818
|
|
799
|
-
variables = self.
|
819
|
+
variables = self.get_suite_variables()
|
800
820
|
|
801
821
|
self._import_default_libraries(variables)
|
802
822
|
self._import_imports(
|
@@ -861,8 +881,9 @@ class Namespace:
|
|
861
881
|
return self.imports_manager.get_command_line_variables()
|
862
882
|
|
863
883
|
def _reset_global_variables(self) -> None:
|
864
|
-
with self._global_variables_lock:
|
884
|
+
with self._global_variables_lock, self._suite_variables_lock:
|
865
885
|
self._global_variables = None
|
886
|
+
self._suite_variables = None
|
866
887
|
|
867
888
|
def get_global_variables(self) -> List[VariableDefinition]:
|
868
889
|
with self._global_variables_lock:
|
@@ -887,13 +908,16 @@ class Namespace:
|
|
887
908
|
) -> Iterator[Tuple[VariableMatcher, VariableDefinition]]:
|
888
909
|
yielded: Dict[VariableMatcher, VariableDefinition] = {}
|
889
910
|
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
911
|
+
test_or_keyword = None
|
912
|
+
|
913
|
+
if nodes:
|
914
|
+
test_or_keyword_nodes = list(
|
915
|
+
itertools.dropwhile(
|
916
|
+
lambda v: not isinstance(v, (TestCase, Keyword)),
|
917
|
+
nodes if nodes else [],
|
918
|
+
)
|
894
919
|
)
|
895
|
-
|
896
|
-
test_or_keyword = test_or_keyword_nodes[0] if test_or_keyword_nodes else None
|
920
|
+
test_or_keyword = test_or_keyword_nodes[0] if test_or_keyword_nodes else None
|
897
921
|
|
898
922
|
for var in chain(
|
899
923
|
*[
|
@@ -921,6 +945,31 @@ class Namespace:
|
|
921
945
|
|
922
946
|
yield var.matcher, var
|
923
947
|
|
948
|
+
def get_suite_variables(
|
949
|
+
self,
|
950
|
+
nodes: Optional[List[ast.AST]] = None,
|
951
|
+
position: Optional[Position] = None,
|
952
|
+
) -> Dict[str, Any]:
|
953
|
+
if nodes:
|
954
|
+
return {
|
955
|
+
v.name: v.value
|
956
|
+
for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
|
957
|
+
if v.has_value
|
958
|
+
}
|
959
|
+
with self._suite_variables_lock:
|
960
|
+
vars = {}
|
961
|
+
|
962
|
+
def check_var(var: VariableDefinition) -> bool:
|
963
|
+
if var.matcher in vars:
|
964
|
+
return False
|
965
|
+
vars[var.matcher] = var
|
966
|
+
|
967
|
+
return var.has_value
|
968
|
+
|
969
|
+
self._suite_variables = {v.name: v.value for v in filter(check_var, self.get_global_variables())}
|
970
|
+
|
971
|
+
return self._suite_variables
|
972
|
+
|
924
973
|
def get_resolvable_variables(
|
925
974
|
self,
|
926
975
|
nodes: Optional[List[ast.AST]] = None,
|
@@ -981,215 +1030,228 @@ class Namespace:
|
|
981
1030
|
|
982
1031
|
return None
|
983
1032
|
|
984
|
-
def
|
1033
|
+
def _import(
|
985
1034
|
self,
|
986
|
-
|
1035
|
+
value: Import,
|
1036
|
+
variables: Optional[Dict[str, Any]],
|
987
1037
|
base_dir: str,
|
988
1038
|
*,
|
989
1039
|
top_level: bool = False,
|
990
|
-
variables: Optional[Dict[str, Any]] = None,
|
991
1040
|
source: Optional[str] = None,
|
992
1041
|
parent_import: Optional[Import] = None,
|
993
|
-
) ->
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1042
|
+
) -> Optional[LibraryEntry]:
|
1043
|
+
result: Optional[LibraryEntry] = None
|
1044
|
+
try:
|
1045
|
+
if isinstance(value, LibraryImport):
|
1046
|
+
if value.name is None:
|
1047
|
+
raise NameSpaceError("Library setting requires value.")
|
1048
|
+
|
1049
|
+
result = self._get_library_entry(
|
1050
|
+
value.name,
|
1051
|
+
value.args,
|
1052
|
+
value.alias,
|
1053
|
+
base_dir,
|
1054
|
+
sentinel=self,
|
1055
|
+
variables=variables,
|
1056
|
+
)
|
1057
|
+
result.import_range = value.range
|
1058
|
+
result.import_source = value.source
|
1059
|
+
result.alias_range = value.alias_range
|
1060
|
+
|
1061
|
+
self._import_entries[value] = result
|
1062
|
+
|
1063
|
+
if (
|
1064
|
+
top_level
|
1065
|
+
and result.library_doc.errors is None
|
1066
|
+
and (len(result.library_doc.keywords) == 0 and not bool(result.library_doc.has_listener))
|
1067
|
+
):
|
1068
|
+
self.append_diagnostics(
|
1069
|
+
range=value.range,
|
1070
|
+
message=f"Imported library '{value.name}' contains no keywords.",
|
1071
|
+
severity=DiagnosticSeverity.WARNING,
|
1072
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1073
|
+
code=Error.LIBRARY_CONTAINS_NO_KEYWORDS,
|
1074
|
+
)
|
1075
|
+
elif isinstance(value, ResourceImport):
|
1076
|
+
if value.name is None:
|
1077
|
+
raise NameSpaceError("Resource setting requires value.")
|
1002
1078
|
|
1003
|
-
|
1079
|
+
source = self.imports_manager.find_resource(value.name, base_dir, variables=variables)
|
1080
|
+
|
1081
|
+
if self.source == source:
|
1082
|
+
if parent_import:
|
1083
|
+
self.append_diagnostics(
|
1084
|
+
range=parent_import.range,
|
1085
|
+
message="Possible circular import.",
|
1086
|
+
severity=DiagnosticSeverity.INFORMATION,
|
1087
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1088
|
+
related_information=(
|
1089
|
+
[
|
1090
|
+
DiagnosticRelatedInformation(
|
1091
|
+
location=Location(
|
1092
|
+
str(Uri.from_path(value.source)),
|
1093
|
+
value.range,
|
1094
|
+
),
|
1095
|
+
message=f"'{Path(self.source).name}' is also imported here.",
|
1096
|
+
)
|
1097
|
+
]
|
1098
|
+
if value.source
|
1099
|
+
else None
|
1100
|
+
),
|
1101
|
+
code=Error.POSSIBLE_CIRCULAR_IMPORT,
|
1102
|
+
)
|
1103
|
+
else:
|
1104
|
+
result = self._get_resource_entry(
|
1004
1105
|
value.name,
|
1005
|
-
value.args,
|
1006
|
-
value.alias,
|
1007
1106
|
base_dir,
|
1008
|
-
sentinel=self,
|
1009
1107
|
variables=variables,
|
1010
1108
|
)
|
1011
1109
|
result.import_range = value.range
|
1012
1110
|
result.import_source = value.source
|
1013
|
-
result.alias_range = value.alias_range
|
1014
1111
|
|
1015
1112
|
self._import_entries[value] = result
|
1016
1113
|
|
1017
|
-
if (
|
1018
|
-
|
1019
|
-
and
|
1020
|
-
and
|
1114
|
+
if top_level and (
|
1115
|
+
not result.library_doc.errors
|
1116
|
+
and top_level
|
1117
|
+
and not result.imports
|
1118
|
+
and not result.variables
|
1119
|
+
and not result.library_doc.keywords
|
1021
1120
|
):
|
1022
1121
|
self.append_diagnostics(
|
1023
1122
|
range=value.range,
|
1024
|
-
message=f"Imported
|
1123
|
+
message=f"Imported resource file '{value.name}' is empty.",
|
1025
1124
|
severity=DiagnosticSeverity.WARNING,
|
1026
1125
|
source=DIAGNOSTICS_SOURCE_NAME,
|
1027
|
-
code=Error.
|
1028
|
-
)
|
1029
|
-
elif isinstance(value, ResourceImport):
|
1030
|
-
if value.name is None:
|
1031
|
-
raise NameSpaceError("Resource setting requires value.")
|
1032
|
-
|
1033
|
-
source = self.imports_manager.find_resource(value.name, base_dir, variables=variables)
|
1034
|
-
|
1035
|
-
if self.source == source:
|
1036
|
-
if parent_import:
|
1037
|
-
self.append_diagnostics(
|
1038
|
-
range=parent_import.range,
|
1039
|
-
message="Possible circular import.",
|
1040
|
-
severity=DiagnosticSeverity.INFORMATION,
|
1041
|
-
source=DIAGNOSTICS_SOURCE_NAME,
|
1042
|
-
related_information=(
|
1043
|
-
[
|
1044
|
-
DiagnosticRelatedInformation(
|
1045
|
-
location=Location(
|
1046
|
-
str(Uri.from_path(value.source)),
|
1047
|
-
value.range,
|
1048
|
-
),
|
1049
|
-
message=f"'{Path(self.source).name}' is also imported here.",
|
1050
|
-
)
|
1051
|
-
]
|
1052
|
-
if value.source
|
1053
|
-
else None
|
1054
|
-
),
|
1055
|
-
code=Error.POSSIBLE_CIRCULAR_IMPORT,
|
1056
|
-
)
|
1057
|
-
else:
|
1058
|
-
result = self._get_resource_entry(
|
1059
|
-
value.name,
|
1060
|
-
base_dir,
|
1061
|
-
variables=variables,
|
1126
|
+
code=Error.RESOURCE_EMPTY,
|
1062
1127
|
)
|
1063
|
-
result.import_range = value.range
|
1064
|
-
result.import_source = value.source
|
1065
|
-
|
1066
|
-
self._import_entries[value] = result
|
1067
|
-
if result.variables:
|
1068
|
-
variables = None
|
1069
|
-
|
1070
|
-
if top_level and (
|
1071
|
-
not result.library_doc.errors
|
1072
|
-
and top_level
|
1073
|
-
and not result.imports
|
1074
|
-
and not result.variables
|
1075
|
-
and not result.library_doc.keywords
|
1076
|
-
):
|
1077
|
-
self.append_diagnostics(
|
1078
|
-
range=value.range,
|
1079
|
-
message=f"Imported resource file '{value.name}' is empty.",
|
1080
|
-
severity=DiagnosticSeverity.WARNING,
|
1081
|
-
source=DIAGNOSTICS_SOURCE_NAME,
|
1082
|
-
code=Error.RESOURCE_EMPTY,
|
1083
|
-
)
|
1084
1128
|
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1129
|
+
elif isinstance(value, VariablesImport):
|
1130
|
+
if value.name is None:
|
1131
|
+
raise NameSpaceError("Variables setting requires value.")
|
1088
1132
|
|
1089
|
-
|
1090
|
-
|
1091
|
-
|
1092
|
-
|
1093
|
-
|
1094
|
-
|
1133
|
+
result = self._get_variables_entry(
|
1134
|
+
value.name,
|
1135
|
+
value.args,
|
1136
|
+
base_dir,
|
1137
|
+
variables=variables,
|
1138
|
+
)
|
1095
1139
|
|
1096
|
-
|
1097
|
-
|
1140
|
+
result.import_range = value.range
|
1141
|
+
result.import_source = value.source
|
1098
1142
|
|
1099
|
-
|
1100
|
-
|
1101
|
-
|
1102
|
-
raise DiagnosticsError("Unknown import type.")
|
1143
|
+
self._import_entries[value] = result
|
1144
|
+
else:
|
1145
|
+
raise DiagnosticsError("Unknown import type.")
|
1103
1146
|
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
|
1108
|
-
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
),
|
1126
|
-
character=0,
|
1147
|
+
if top_level and result is not None:
|
1148
|
+
if result.library_doc.source is not None and result.library_doc.errors:
|
1149
|
+
if any(err.source and Path(err.source).is_absolute() for err in result.library_doc.errors):
|
1150
|
+
self.append_diagnostics(
|
1151
|
+
range=value.range,
|
1152
|
+
message="Import definition contains errors.",
|
1153
|
+
severity=DiagnosticSeverity.ERROR,
|
1154
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1155
|
+
related_information=[
|
1156
|
+
DiagnosticRelatedInformation(
|
1157
|
+
location=Location(
|
1158
|
+
uri=str(Uri.from_path(err.source)),
|
1159
|
+
range=Range(
|
1160
|
+
start=Position(
|
1161
|
+
line=(
|
1162
|
+
err.line_no - 1
|
1163
|
+
if err.line_no is not None
|
1164
|
+
else max(
|
1165
|
+
result.library_doc.line_no,
|
1166
|
+
0,
|
1167
|
+
)
|
1127
1168
|
),
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
|
1133
|
-
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
1169
|
+
character=0,
|
1170
|
+
),
|
1171
|
+
end=Position(
|
1172
|
+
line=(
|
1173
|
+
err.line_no - 1
|
1174
|
+
if err.line_no is not None
|
1175
|
+
else max(
|
1176
|
+
result.library_doc.line_no,
|
1177
|
+
0,
|
1178
|
+
)
|
1138
1179
|
),
|
1180
|
+
character=0,
|
1139
1181
|
),
|
1140
1182
|
),
|
1141
|
-
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
|
1154
|
-
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1183
|
+
),
|
1184
|
+
message=err.message,
|
1185
|
+
)
|
1186
|
+
for err in result.library_doc.errors
|
1187
|
+
if err.source is not None
|
1188
|
+
],
|
1189
|
+
code=Error.IMPORT_CONTAINS_ERRORS,
|
1190
|
+
)
|
1191
|
+
for err in filter(
|
1192
|
+
lambda e: e.source is None or not Path(e.source).is_absolute(),
|
1193
|
+
result.library_doc.errors,
|
1194
|
+
):
|
1195
|
+
self.append_diagnostics(
|
1196
|
+
range=value.range,
|
1197
|
+
message=err.message,
|
1198
|
+
severity=DiagnosticSeverity.ERROR,
|
1199
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1200
|
+
code=err.type_name,
|
1201
|
+
)
|
1202
|
+
elif result.library_doc.errors is not None:
|
1203
|
+
for err in result.library_doc.errors:
|
1204
|
+
self.append_diagnostics(
|
1205
|
+
range=value.range,
|
1206
|
+
message=err.message,
|
1207
|
+
severity=DiagnosticSeverity.ERROR,
|
1208
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1209
|
+
code=err.type_name,
|
1210
|
+
)
|
1168
1211
|
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1212
|
+
except (SystemExit, KeyboardInterrupt):
|
1213
|
+
raise
|
1214
|
+
except BaseException as e:
|
1215
|
+
if top_level:
|
1216
|
+
self.append_diagnostics(
|
1217
|
+
range=value.range,
|
1218
|
+
message=str(e),
|
1219
|
+
severity=DiagnosticSeverity.ERROR,
|
1220
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1221
|
+
code=type(e).__qualname__,
|
1222
|
+
)
|
1223
|
+
finally:
|
1224
|
+
self._reset_global_variables()
|
1182
1225
|
|
1183
|
-
|
1226
|
+
return result
|
1227
|
+
|
1228
|
+
def _import_imports(
|
1229
|
+
self,
|
1230
|
+
imports: Iterable[Import],
|
1231
|
+
base_dir: str,
|
1232
|
+
*,
|
1233
|
+
top_level: bool = False,
|
1234
|
+
variables: Optional[Dict[str, Any]] = None,
|
1235
|
+
source: Optional[str] = None,
|
1236
|
+
parent_import: Optional[Import] = None,
|
1237
|
+
depth: int = 0,
|
1238
|
+
) -> Optional[Dict[str, Any]]:
|
1184
1239
|
|
1185
1240
|
current_time = time.monotonic()
|
1186
|
-
self._logger.debug(lambda: f"start imports for {self.document if top_level else source}")
|
1241
|
+
self._logger.debug(lambda: f"{' '*depth}start imports for {self.document if top_level else source}")
|
1187
1242
|
try:
|
1188
1243
|
for imp in imports:
|
1189
1244
|
if variables is None:
|
1190
|
-
variables = self.
|
1245
|
+
variables = self.get_suite_variables()
|
1191
1246
|
|
1192
|
-
entry
|
1247
|
+
entry = self._import(
|
1248
|
+
imp,
|
1249
|
+
variables=variables,
|
1250
|
+
base_dir=base_dir,
|
1251
|
+
top_level=top_level,
|
1252
|
+
source=source,
|
1253
|
+
parent_import=parent_import,
|
1254
|
+
)
|
1193
1255
|
|
1194
1256
|
if entry is not None:
|
1195
1257
|
if isinstance(entry, ResourceEntry):
|
@@ -1201,14 +1263,18 @@ class Namespace:
|
|
1201
1263
|
|
1202
1264
|
if already_imported_resources is None and entry.library_doc.source != self.source:
|
1203
1265
|
self._resources[entry.import_name] = entry
|
1266
|
+
if entry.variables:
|
1267
|
+
variables = self.get_suite_variables()
|
1268
|
+
|
1204
1269
|
try:
|
1205
|
-
self._import_imports(
|
1270
|
+
variables = self._import_imports(
|
1206
1271
|
entry.imports,
|
1207
1272
|
str(Path(entry.library_doc.source).parent),
|
1208
1273
|
top_level=False,
|
1209
1274
|
variables=variables,
|
1210
1275
|
source=entry.library_doc.source,
|
1211
1276
|
parent_import=imp if top_level else parent_import,
|
1277
|
+
depth=depth + 1,
|
1212
1278
|
)
|
1213
1279
|
except (SystemExit, KeyboardInterrupt):
|
1214
1280
|
raise
|
@@ -1221,56 +1287,59 @@ class Namespace:
|
|
1221
1287
|
source=DIAGNOSTICS_SOURCE_NAME,
|
1222
1288
|
code=type(e).__qualname__,
|
1223
1289
|
)
|
1224
|
-
|
1225
|
-
if
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
1243
|
-
|
1244
|
-
|
1245
|
-
|
1246
|
-
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
else None
|
1257
|
-
),
|
1258
|
-
code=Error.RESOURCE_ALREADY_IMPORTED,
|
1259
|
-
)
|
1290
|
+
elif top_level:
|
1291
|
+
if entry.library_doc.source == self.source:
|
1292
|
+
self.append_diagnostics(
|
1293
|
+
range=entry.import_range,
|
1294
|
+
message="Recursive resource import.",
|
1295
|
+
severity=DiagnosticSeverity.INFORMATION,
|
1296
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1297
|
+
code=Error.RECURSIVE_IMPORT,
|
1298
|
+
)
|
1299
|
+
elif (
|
1300
|
+
already_imported_resources is not None and already_imported_resources.library_doc.source
|
1301
|
+
):
|
1302
|
+
self.append_diagnostics(
|
1303
|
+
range=entry.import_range,
|
1304
|
+
message=f"Resource {entry} already imported.",
|
1305
|
+
severity=DiagnosticSeverity.INFORMATION,
|
1306
|
+
source=DIAGNOSTICS_SOURCE_NAME,
|
1307
|
+
related_information=(
|
1308
|
+
[
|
1309
|
+
DiagnosticRelatedInformation(
|
1310
|
+
location=Location(
|
1311
|
+
uri=str(Uri.from_path(already_imported_resources.import_source)),
|
1312
|
+
range=already_imported_resources.import_range,
|
1313
|
+
),
|
1314
|
+
message="",
|
1315
|
+
)
|
1316
|
+
]
|
1317
|
+
if already_imported_resources.import_source
|
1318
|
+
else None
|
1319
|
+
),
|
1320
|
+
code=Error.RESOURCE_ALREADY_IMPORTED,
|
1321
|
+
)
|
1260
1322
|
|
1261
1323
|
elif isinstance(entry, VariablesEntry):
|
1262
|
-
already_imported_variables =
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1324
|
+
already_imported_variables = next(
|
1325
|
+
(
|
1326
|
+
e
|
1327
|
+
for e in self._variables.values()
|
1328
|
+
if e.library_doc.source == entry.library_doc.source
|
1329
|
+
and e.alias == entry.alias
|
1330
|
+
and e.args == entry.args
|
1331
|
+
),
|
1332
|
+
None,
|
1333
|
+
)
|
1269
1334
|
if (
|
1270
|
-
|
1271
|
-
and
|
1272
|
-
and
|
1335
|
+
already_imported_variables is None
|
1336
|
+
and entry.library_doc is not None
|
1337
|
+
and entry.library_doc.source_or_origin
|
1273
1338
|
):
|
1339
|
+
self._variables[entry.library_doc.source_or_origin] = entry
|
1340
|
+
if entry.variables:
|
1341
|
+
variables = self.get_suite_variables()
|
1342
|
+
elif top_level and already_imported_variables and already_imported_variables.library_doc.source:
|
1274
1343
|
self.append_diagnostics(
|
1275
1344
|
range=entry.import_range,
|
1276
1345
|
message=f'Variables "{entry}" already imported.',
|
@@ -1280,21 +1349,18 @@ class Namespace:
|
|
1280
1349
|
[
|
1281
1350
|
DiagnosticRelatedInformation(
|
1282
1351
|
location=Location(
|
1283
|
-
uri=str(Uri.from_path(already_imported_variables
|
1284
|
-
range=already_imported_variables
|
1352
|
+
uri=str(Uri.from_path(already_imported_variables.import_source)),
|
1353
|
+
range=already_imported_variables.import_range,
|
1285
1354
|
),
|
1286
1355
|
message="",
|
1287
1356
|
)
|
1288
1357
|
]
|
1289
|
-
if already_imported_variables
|
1358
|
+
if already_imported_variables.import_source
|
1290
1359
|
else None
|
1291
1360
|
),
|
1292
1361
|
code=Error.VARIABLES_ALREADY_IMPORTED,
|
1293
1362
|
)
|
1294
1363
|
|
1295
|
-
if entry.library_doc is not None and entry.library_doc.source_or_origin:
|
1296
|
-
self._variables[entry.library_doc.source_or_origin] = entry
|
1297
|
-
|
1298
1364
|
elif isinstance(entry, LibraryEntry):
|
1299
1365
|
if top_level and entry.name == BUILTIN_LIBRARY_NAME and entry.alias is None:
|
1300
1366
|
self.append_diagnostics(
|
@@ -1320,15 +1386,23 @@ class Namespace:
|
|
1320
1386
|
)
|
1321
1387
|
continue
|
1322
1388
|
|
1323
|
-
already_imported_library =
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1389
|
+
already_imported_library = next(
|
1390
|
+
(
|
1391
|
+
e
|
1392
|
+
for e in self._libraries.values()
|
1393
|
+
if e.library_doc.source == entry.library_doc.source
|
1394
|
+
and e.library_doc.member_name == entry.library_doc.member_name
|
1395
|
+
and e.alias == entry.alias
|
1396
|
+
and e.args == entry.args
|
1397
|
+
),
|
1398
|
+
None,
|
1399
|
+
)
|
1400
|
+
if (
|
1401
|
+
already_imported_library is None
|
1402
|
+
and (entry.alias or entry.name or entry.import_name) not in self._libraries
|
1403
|
+
):
|
1404
|
+
self._libraries[entry.alias or entry.name or entry.import_name] = entry
|
1405
|
+
elif top_level and already_imported_library and already_imported_library.library_doc.source:
|
1332
1406
|
self.append_diagnostics(
|
1333
1407
|
range=entry.import_range,
|
1334
1408
|
message=f'Library "{entry}" already imported.',
|
@@ -1338,26 +1412,26 @@ class Namespace:
|
|
1338
1412
|
[
|
1339
1413
|
DiagnosticRelatedInformation(
|
1340
1414
|
location=Location(
|
1341
|
-
uri=str(Uri.from_path(already_imported_library
|
1342
|
-
range=already_imported_library
|
1415
|
+
uri=str(Uri.from_path(already_imported_library.import_source)),
|
1416
|
+
range=already_imported_library.import_range,
|
1343
1417
|
),
|
1344
1418
|
message="",
|
1345
1419
|
)
|
1346
1420
|
]
|
1347
|
-
if already_imported_library
|
1421
|
+
if already_imported_library.import_source
|
1348
1422
|
else None
|
1349
1423
|
),
|
1350
1424
|
code=Error.LIBRARY_ALREADY_IMPORTED,
|
1351
1425
|
)
|
1352
1426
|
|
1353
|
-
if (entry.alias or entry.name or entry.import_name) not in self._libraries:
|
1354
|
-
self._libraries[entry.alias or entry.name or entry.import_name] = entry
|
1355
1427
|
finally:
|
1356
1428
|
self._logger.debug(
|
1357
|
-
lambda: "end
|
1429
|
+
lambda: f"{' '*depth}end imports for "
|
1358
1430
|
f"{self.document if top_level else source} in {time.monotonic() - current_time}s"
|
1359
1431
|
)
|
1360
1432
|
|
1433
|
+
return variables
|
1434
|
+
|
1361
1435
|
def _import_default_libraries(self, variables: Optional[Dict[str, Any]] = None) -> None:
|
1362
1436
|
def _import_lib(library: str, variables: Optional[Dict[str, Any]] = None) -> Optional[LibraryEntry]:
|
1363
1437
|
try:
|
@@ -1383,8 +1457,11 @@ class Namespace:
|
|
1383
1457
|
|
1384
1458
|
self._logger.debug(lambda: f"start import default libraries for document {self.document}")
|
1385
1459
|
try:
|
1460
|
+
if variables is None:
|
1461
|
+
variables = self.get_suite_variables()
|
1462
|
+
|
1386
1463
|
for library in DEFAULT_LIBRARIES:
|
1387
|
-
e = _import_lib(library, variables
|
1464
|
+
e = _import_lib(library, variables)
|
1388
1465
|
if e is not None:
|
1389
1466
|
self._libraries[e.alias or e.name or e.import_name] = e
|
1390
1467
|
finally:
|
@@ -1402,12 +1479,15 @@ class Namespace:
|
|
1402
1479
|
sentinel: Any = None,
|
1403
1480
|
variables: Optional[Dict[str, Any]] = None,
|
1404
1481
|
) -> LibraryEntry:
|
1482
|
+
if variables is None:
|
1483
|
+
variables = self.get_suite_variables()
|
1484
|
+
|
1405
1485
|
library_doc = self.imports_manager.get_libdoc_for_library_import(
|
1406
1486
|
name,
|
1407
1487
|
args,
|
1408
1488
|
base_dir=base_dir,
|
1409
1489
|
sentinel=None if is_default_library else sentinel,
|
1410
|
-
variables=variables
|
1490
|
+
variables=variables,
|
1411
1491
|
)
|
1412
1492
|
|
1413
1493
|
return LibraryEntry(
|
@@ -1441,14 +1521,11 @@ class Namespace:
|
|
1441
1521
|
*,
|
1442
1522
|
variables: Optional[Dict[str, Any]] = None,
|
1443
1523
|
) -> ResourceEntry:
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
) = self.imports_manager.get_namespace_and_libdoc_for_resource_import(
|
1448
|
-
name,
|
1449
|
-
base_dir,
|
1450
|
-
sentinel=self,
|
1451
|
-
variables=variables or self.get_resolvable_variables(),
|
1524
|
+
if variables is None:
|
1525
|
+
variables = self.get_suite_variables()
|
1526
|
+
|
1527
|
+
(namespace, library_doc) = self.imports_manager.get_namespace_and_libdoc_for_resource_import(
|
1528
|
+
name, base_dir, sentinel=self, variables=variables
|
1452
1529
|
)
|
1453
1530
|
|
1454
1531
|
return ResourceEntry(
|
@@ -1481,12 +1558,15 @@ class Namespace:
|
|
1481
1558
|
*,
|
1482
1559
|
variables: Optional[Dict[str, Any]] = None,
|
1483
1560
|
) -> VariablesEntry:
|
1561
|
+
if variables is None:
|
1562
|
+
variables = self.get_suite_variables()
|
1563
|
+
|
1484
1564
|
library_doc = self.imports_manager.get_libdoc_for_variables_import(
|
1485
1565
|
name,
|
1486
1566
|
args,
|
1487
1567
|
base_dir=base_dir,
|
1488
1568
|
sentinel=self,
|
1489
|
-
variables=variables
|
1569
|
+
variables=variables,
|
1490
1570
|
)
|
1491
1571
|
|
1492
1572
|
return VariablesEntry(
|
@@ -1592,6 +1672,10 @@ class Namespace:
|
|
1592
1672
|
)
|
1593
1673
|
)
|
1594
1674
|
|
1675
|
+
def is_analyzed(self) -> bool:
|
1676
|
+
with self._analyze_lock:
|
1677
|
+
return self._analyzed
|
1678
|
+
|
1595
1679
|
@_logger.call(condition=lambda self: not self._analyzed)
|
1596
1680
|
def analyze(self) -> None:
|
1597
1681
|
import time
|
@@ -1602,6 +1686,8 @@ class Namespace:
|
|
1602
1686
|
if not self._analyzed:
|
1603
1687
|
canceled = False
|
1604
1688
|
|
1689
|
+
self.ensure_initialized()
|
1690
|
+
|
1605
1691
|
self._logger.debug(lambda: f"start analyze {self.document}")
|
1606
1692
|
start_time = time.monotonic()
|
1607
1693
|
|