robotcode-robot 0.76.0__tar.gz → 0.76.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/PKG-INFO +2 -2
  2. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/pyproject.toml +1 -1
  3. robotcode_robot-0.76.1/src/robotcode/robot/__version__.py +1 -0
  4. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/document_cache_helper.py +40 -4
  5. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/entities.py +4 -5
  6. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/imports_manager.py +8 -5
  7. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/model_helper.py +1 -1
  8. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/namespace.py +75 -29
  9. robotcode_robot-0.76.0/src/robotcode/robot/__version__.py +0 -1
  10. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/.gitignore +0 -0
  11. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/LICENSE.txt +0 -0
  12. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/README.md +0 -0
  13. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/__init__.py +0 -0
  14. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/config/__init__.py +0 -0
  15. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/config/loader.py +0 -0
  16. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/config/model.py +0 -0
  17. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/config/utils.py +0 -0
  18. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/__init__.py +0 -0
  19. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/errors.py +0 -0
  20. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/library_doc.py +0 -0
  21. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/namespace_analyzer.py +0 -0
  22. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/diagnostics/workspace_config.py +0 -0
  23. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/py.typed +0 -0
  24. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/__init__.py +0 -0
  25. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/ast.py +0 -0
  26. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/markdownformatter.py +0 -0
  27. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/match.py +0 -0
  28. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/robot_path.py +0 -0
  29. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/stubs.py +0 -0
  30. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/variables.py +0 -0
  31. {robotcode_robot-0.76.0 → robotcode_robot-0.76.1}/src/robotcode/robot/utils/visitor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: robotcode-robot
3
- Version: 0.76.0
3
+ Version: 0.76.1
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://github.com/sponsors/d-biehl
@@ -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.76.0
29
+ Requires-Dist: robotcode-core==0.76.1
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
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "robotframework>=4.1.0",
30
30
  "tomli>=1.1.0; python_version < '3.11'",
31
31
  "platformdirs>=3.2.0,<4.2.0",
32
- "robotcode-core==0.76.0",
32
+ "robotcode-core==0.76.1",
33
33
  ]
34
34
  dynamic = ["version"]
35
35
 
@@ -0,0 +1 @@
1
+ __version__ = "0.76.1"
@@ -22,7 +22,6 @@ from robot.parsing.lexer.tokens import Token
22
22
  from robotcode.core.documents_manager import DocumentsManager
23
23
  from robotcode.core.event import event
24
24
  from robotcode.core.filewatcher import FileWatcherManagerBase
25
- from robotcode.core.language import language_id_filter
26
25
  from robotcode.core.text_document import TextDocument
27
26
  from robotcode.core.uri import Uri
28
27
  from robotcode.core.utils.logging import LoggingDescriptor
@@ -32,6 +31,7 @@ from ..config.model import RobotBaseProfile
32
31
  from ..utils import get_robot_version
33
32
  from ..utils.stubs import Languages
34
33
  from .imports_manager import ImportsManager
34
+ from .library_doc import LibraryDoc
35
35
  from .namespace import DocumentType, Namespace
36
36
  from .workspace_config import AnalysisRobotConfig, CacheConfig, RobotConfig
37
37
 
@@ -421,15 +421,21 @@ class DocumentsCacheHelper:
421
421
  def __get_general_namespace(self, document: TextDocument) -> Namespace:
422
422
  return self.__get_namespace_for_document_type(document, DocumentType.GENERAL)
423
423
 
424
+ @event
425
+ def namespace_initialized(sender, namespace: Namespace) -> None: ...
426
+
424
427
  @event
425
428
  def namespace_invalidated(sender, namespace: Namespace) -> None: ...
426
429
 
427
430
  def __invalidate_namespace(self, sender: Namespace) -> None:
428
431
  document = sender.document
429
432
  if document is not None:
430
- document.invalidate_cache()
433
+ document.remove_cache_entry(self.__get_general_namespace)
434
+ document.remove_cache_entry(self.__get_init_namespace)
435
+ document.remove_cache_entry(self.__get_resource_namespace)
436
+ document.remove_cache_entry(self.__get_namespace)
431
437
 
432
- self.namespace_invalidated(self, sender, callback_filter=language_id_filter(document))
438
+ self.namespace_invalidated(self, sender)
433
439
 
434
440
  def __namespace_initialized(self, sender: Namespace) -> None:
435
441
  if sender.document is not None:
@@ -437,6 +443,7 @@ class DocumentsCacheHelper:
437
443
  lambda: f"Save initialized Namespace: {sender.document.uri if sender.document else None}"
438
444
  )
439
445
  sender.document.set_data(self.INITIALIZED_NAMESPACE, sender)
446
+ self.namespace_initialized(self, sender)
440
447
 
441
448
  def get_initialized_namespace(self, document: TextDocument) -> Namespace:
442
449
  result: Optional[Namespace] = document.get_data(self.INITIALIZED_NAMESPACE)
@@ -445,6 +452,11 @@ class DocumentsCacheHelper:
445
452
  result = self.get_namespace(document)
446
453
  return result
447
454
 
455
+ def get_only_initialized_namespace(self, document: TextDocument) -> Optional[Namespace]:
456
+ result: Optional[Namespace] = document.get_data(self.INITIALIZED_NAMESPACE)
457
+
458
+ return result
459
+
448
460
  def __get_namespace_for_document_type(
449
461
  self, document: TextDocument, document_type: Optional[DocumentType]
450
462
  ) -> Namespace:
@@ -495,7 +507,7 @@ class DocumentsCacheHelper:
495
507
  ]
496
508
 
497
509
  analysis_config = self.workspace.get_configuration(AnalysisRobotConfig, root_uri)
498
- return ImportsManager(
510
+ result = ImportsManager(
499
511
  self.documents_manager,
500
512
  self.file_watcher_manager,
501
513
  self,
@@ -510,6 +522,30 @@ class DocumentsCacheHelper:
510
522
  cache_base_path,
511
523
  )
512
524
 
525
+ result.libraries_changed.add(self._on_libraries_changed)
526
+ result.resources_changed.add(self._on_resources_changed)
527
+ result.variables_changed.add(self._on_variables_changed)
528
+
529
+ return result
530
+
531
+ @event
532
+ def libraries_changed(sender, libraries: List[LibraryDoc]) -> None: ...
533
+
534
+ @event
535
+ def resources_changed(sender, resources: List[LibraryDoc]) -> None: ...
536
+
537
+ @event
538
+ def variables_changed(sender, variables: List[LibraryDoc]) -> None: ...
539
+
540
+ def _on_libraries_changed(self, sender: ImportsManager, libraries: List[LibraryDoc]) -> None:
541
+ self.libraries_changed(self, libraries)
542
+
543
+ def _on_resources_changed(self, sender: ImportsManager, resources: List[LibraryDoc]) -> None:
544
+ self.resources_changed(self, resources)
545
+
546
+ def _on_variables_changed(self, sender: ImportsManager, variables: List[LibraryDoc]) -> None:
547
+ self.variables_changed(self, variables)
548
+
513
549
  def default_imports_manager(self) -> ImportsManager:
514
550
  with self._imports_managers_lock:
515
551
  if self._default_imports_manager is None:
@@ -195,11 +195,10 @@ class VariableDefinition(SourceEntity):
195
195
  value: Any = field(default=None, compare=False)
196
196
  value_is_native: bool = field(default=False, compare=False)
197
197
 
198
- @property
199
- def matcher(self) -> VariableMatcher:
200
- if not hasattr(self, "__matcher"):
201
- self.__matcher = VariableMatcher(self.name)
202
- return self.__matcher
198
+ matcher: VariableMatcher = field(init=False, compare=False)
199
+
200
+ def __post_init__(self) -> None:
201
+ self.matcher = VariableMatcher(self.name)
203
202
 
204
203
  @single_call
205
204
  def __hash__(self) -> int:
@@ -503,8 +503,8 @@ class ImportsManager:
503
503
  super().__init__()
504
504
 
505
505
  self.documents_manager = documents_manager
506
- self.documents_manager.did_create_uri.add(self.possible_imports_modified)
507
- self.documents_manager.did_change.add(self.possible_resource_document_modified)
506
+ self.documents_manager.did_create_uri.add(self._on_possible_imports_modified)
507
+ self.documents_manager.did_change.add(self._on_possible_resource_document_modified)
508
508
 
509
509
  self.file_watcher_manager: FileWatcherManagerBase = (
510
510
  file_watcher_manager if file_watcher_manager is not None else FileWatcherManagerDummy()
@@ -685,12 +685,15 @@ class ImportsManager:
685
685
  @event
686
686
  def imports_changed(sender, uri: DocumentUri) -> None: ...
687
687
 
688
- def possible_imports_modified(self, sender: Any, uri: DocumentUri) -> None:
688
+ def _on_possible_imports_modified(self, sender: Any, uri: DocumentUri) -> None:
689
689
  # TODO: do we really need this?
690
690
  self.imports_changed(self, uri)
691
691
 
692
692
  @language_id("robotframework")
693
- def possible_resource_document_modified(self, sender: Any, document: TextDocument) -> None:
693
+ def _on_possible_resource_document_modified(self, sender: Any, document: TextDocument) -> None:
694
+ run_as_task(self.__on_possible_resource_document_modified, sender, document)
695
+
696
+ def __on_possible_resource_document_modified(self, sender: Any, document: TextDocument) -> None:
694
697
  with self._resource_document_changed_timer_lock:
695
698
  if document in self._resource_document_changed_documents:
696
699
  return
@@ -714,7 +717,7 @@ class ImportsManager:
714
717
  self._resource_document_changed_documents = set()
715
718
 
716
719
  for document in documents:
717
- run_as_task(self.__resource_document_changed, document).result()
720
+ self.__resource_document_changed(document)
718
721
 
719
722
  def __resource_document_changed(self, document: TextDocument) -> None:
720
723
  resource_changed: List[LibraryDoc] = []
@@ -290,7 +290,7 @@ class ModelHelper:
290
290
  sub_token.lineno,
291
291
  sub_token.end_col_offset,
292
292
  namespace.source,
293
- tokval,
293
+ f"${{{tokval}}}",
294
294
  sub_token,
295
295
  ),
296
296
  )
@@ -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.imports_changed)
604
- self.imports_manager.libraries_changed.add(self.libraries_changed)
605
- self.imports_manager.resources_changed.add(self.resources_changed)
606
- self.imports_manager.variables_changed.add(self.variables_changed)
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 imports_changed(self, sender: Any, uri: DocumentUri) -> None:
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 libraries_changed(self, sender: Any, libraries: List[LibraryDoc]) -> None:
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 resources_changed(self, sender: Any, resources: List[LibraryDoc]) -> None:
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 variables_changed(self, sender: Any, variables: List[LibraryDoc]) -> None:
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,19 +696,20 @@ class Namespace:
684
696
 
685
697
  def _invalidate(self) -> None:
686
698
  self._invalid = True
687
- self.imports_manager.imports_changed.remove(self.imports_changed)
688
- self.imports_manager.libraries_changed.remove(self.libraries_changed)
689
- self.imports_manager.resources_changed.remove(self.resources_changed)
690
- self.imports_manager.variables_changed.remove(self.variables_changed)
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)
691
703
 
692
704
  @_logger.call
693
- def invalidate(self) -> None:
705
+ def invalidate(self) -> bool:
694
706
  with self._initialize_lock:
695
707
  if self._invalid:
696
- return
708
+ return False
697
709
 
698
710
  self._invalidate()
699
711
  self.has_invalidated(self)
712
+ return True
700
713
 
701
714
  @_logger.call
702
715
  def get_diagnostics(self) -> List[Diagnostic]:
@@ -803,7 +816,7 @@ class Namespace:
803
816
 
804
817
  imports = self.get_imports()
805
818
 
806
- variables = self.get_resolvable_variables()
819
+ variables = self.get_suite_variables()
807
820
 
808
821
  self._import_default_libraries(variables)
809
822
  self._import_imports(
@@ -868,8 +881,9 @@ class Namespace:
868
881
  return self.imports_manager.get_command_line_variables()
869
882
 
870
883
  def _reset_global_variables(self) -> None:
871
- with self._global_variables_lock:
884
+ with self._global_variables_lock, self._suite_variables_lock:
872
885
  self._global_variables = None
886
+ self._suite_variables = None
873
887
 
874
888
  def get_global_variables(self) -> List[VariableDefinition]:
875
889
  with self._global_variables_lock:
@@ -894,13 +908,16 @@ class Namespace:
894
908
  ) -> Iterator[Tuple[VariableMatcher, VariableDefinition]]:
895
909
  yielded: Dict[VariableMatcher, VariableDefinition] = {}
896
910
 
897
- test_or_keyword_nodes = list(
898
- itertools.dropwhile(
899
- lambda v: not isinstance(v, (TestCase, Keyword)),
900
- nodes if nodes else [],
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
+ )
901
919
  )
902
- )
903
- 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
904
921
 
905
922
  for var in chain(
906
923
  *[
@@ -928,6 +945,31 @@ class Namespace:
928
945
 
929
946
  yield var.matcher, var
930
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
+
931
973
  def get_resolvable_variables(
932
974
  self,
933
975
  nodes: Optional[List[ast.AST]] = None,
@@ -1200,7 +1242,7 @@ class Namespace:
1200
1242
  try:
1201
1243
  for imp in imports:
1202
1244
  if variables is None:
1203
- variables = self.get_resolvable_variables()
1245
+ variables = self.get_suite_variables()
1204
1246
 
1205
1247
  entry = self._import(
1206
1248
  imp,
@@ -1222,7 +1264,7 @@ class Namespace:
1222
1264
  if already_imported_resources is None and entry.library_doc.source != self.source:
1223
1265
  self._resources[entry.import_name] = entry
1224
1266
  if entry.variables:
1225
- variables = self.get_resolvable_variables()
1267
+ variables = self.get_suite_variables()
1226
1268
 
1227
1269
  try:
1228
1270
  variables = self._import_imports(
@@ -1296,7 +1338,7 @@ class Namespace:
1296
1338
  ):
1297
1339
  self._variables[entry.library_doc.source_or_origin] = entry
1298
1340
  if entry.variables:
1299
- variables = self.get_resolvable_variables()
1341
+ variables = self.get_suite_variables()
1300
1342
  elif top_level and already_imported_variables and already_imported_variables.library_doc.source:
1301
1343
  self.append_diagnostics(
1302
1344
  range=entry.import_range,
@@ -1416,7 +1458,7 @@ class Namespace:
1416
1458
  self._logger.debug(lambda: f"start import default libraries for document {self.document}")
1417
1459
  try:
1418
1460
  if variables is None:
1419
- variables = self.get_resolvable_variables()
1461
+ variables = self.get_suite_variables()
1420
1462
 
1421
1463
  for library in DEFAULT_LIBRARIES:
1422
1464
  e = _import_lib(library, variables)
@@ -1438,7 +1480,7 @@ class Namespace:
1438
1480
  variables: Optional[Dict[str, Any]] = None,
1439
1481
  ) -> LibraryEntry:
1440
1482
  if variables is None:
1441
- variables = self.get_resolvable_variables()
1483
+ variables = self.get_suite_variables()
1442
1484
 
1443
1485
  library_doc = self.imports_manager.get_libdoc_for_library_import(
1444
1486
  name,
@@ -1480,7 +1522,7 @@ class Namespace:
1480
1522
  variables: Optional[Dict[str, Any]] = None,
1481
1523
  ) -> ResourceEntry:
1482
1524
  if variables is None:
1483
- variables = self.get_resolvable_variables()
1525
+ variables = self.get_suite_variables()
1484
1526
 
1485
1527
  (namespace, library_doc) = self.imports_manager.get_namespace_and_libdoc_for_resource_import(
1486
1528
  name, base_dir, sentinel=self, variables=variables
@@ -1517,7 +1559,7 @@ class Namespace:
1517
1559
  variables: Optional[Dict[str, Any]] = None,
1518
1560
  ) -> VariablesEntry:
1519
1561
  if variables is None:
1520
- variables = self.get_resolvable_variables()
1562
+ variables = self.get_suite_variables()
1521
1563
 
1522
1564
  library_doc = self.imports_manager.get_libdoc_for_variables_import(
1523
1565
  name,
@@ -1630,6 +1672,10 @@ class Namespace:
1630
1672
  )
1631
1673
  )
1632
1674
 
1675
+ def is_analyzed(self) -> bool:
1676
+ with self._analyze_lock:
1677
+ return self._analyzed
1678
+
1633
1679
  @_logger.call(condition=lambda self: not self._analyzed)
1634
1680
  def analyze(self) -> None:
1635
1681
  import time
@@ -1 +0,0 @@
1
- __version__ = "0.76.0"