robotcode-robot 0.91.0__py3-none-any.whl → 0.93.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/config/loader.py +75 -21
- robotcode/robot/config/model.py +105 -100
- robotcode/robot/config/utils.py +4 -2
- robotcode/robot/diagnostics/diagnostics_modifier.py +80 -17
- robotcode/robot/diagnostics/document_cache_helper.py +25 -7
- robotcode/robot/diagnostics/entities.py +2 -2
- robotcode/robot/diagnostics/imports_manager.py +79 -64
- robotcode/robot/diagnostics/library_doc.py +25 -8
- robotcode/robot/diagnostics/namespace.py +105 -102
- robotcode/robot/diagnostics/workspace_config.py +17 -0
- robotcode/robot/utils/ast.py +34 -7
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/METADATA +2 -2
- robotcode_robot-0.93.0.dist-info/RECORD +30 -0
- robotcode_robot-0.91.0.dist-info/RECORD +0 -30
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/WHEEL +0 -0
- {robotcode_robot-0.91.0.dist-info → robotcode_robot-0.93.0.dist-info}/licenses/LICENSE.txt +0 -0
| @@ -694,7 +694,14 @@ class Namespace: | |
| 694 694 | 
             
                    self._own_variables: Optional[List[VariableDefinition]] = None
         | 
| 695 695 | 
             
                    self._own_variables_lock = RLock(default_timeout=120, name="Namespace.own_variables")
         | 
| 696 696 | 
             
                    self._global_variables: Optional[List[VariableDefinition]] = None
         | 
| 697 | 
            +
                    self._global_variables_dict: Optional[Dict[VariableMatcher, VariableDefinition]] = None
         | 
| 697 698 | 
             
                    self._global_variables_lock = RLock(default_timeout=120, name="Namespace.global_variables")
         | 
| 699 | 
            +
                    self._global_variables_dict_lock = RLock(default_timeout=120, name="Namespace.global_variables_dict")
         | 
| 700 | 
            +
             | 
| 701 | 
            +
                    self._global_resolvable_variables: Optional[Dict[str, Any]] = None
         | 
| 702 | 
            +
                    self._global_resolvable_variables_lock = RLock(
         | 
| 703 | 
            +
                        default_timeout=120, name="Namespace._global_resolvable_variables_lock"
         | 
| 704 | 
            +
                    )
         | 
| 698 705 |  | 
| 699 706 | 
             
                    self._suite_variables: Optional[Dict[str, Any]] = None
         | 
| 700 707 | 
             
                    self._suite_variables_lock = RLock(default_timeout=120, name="Namespace.global_variables")
         | 
| @@ -993,9 +1000,12 @@ class Namespace: | |
| 993 1000 | 
             
                    return self.imports_manager.get_command_line_variables()
         | 
| 994 1001 |  | 
| 995 1002 | 
             
                def _reset_global_variables(self) -> None:
         | 
| 996 | 
            -
                    with self._global_variables_lock, self._suite_variables_lock:
         | 
| 997 | 
            -
                        self. | 
| 998 | 
            -
             | 
| 1003 | 
            +
                    with self._global_variables_lock, self._global_variables_dict_lock, self._suite_variables_lock:
         | 
| 1004 | 
            +
                        with self._global_resolvable_variables_lock:
         | 
| 1005 | 
            +
                            self._global_variables = None
         | 
| 1006 | 
            +
                            self._global_variables_dict = None
         | 
| 1007 | 
            +
                            self._suite_variables = None
         | 
| 1008 | 
            +
                            self._global_resolvable_variables = None
         | 
| 999 1009 |  | 
| 1000 1010 | 
             
                def get_global_variables(self) -> List[VariableDefinition]:
         | 
| 1001 1011 | 
             
                    with self._global_variables_lock:
         | 
| @@ -1012,12 +1022,20 @@ class Namespace: | |
| 1012 1022 |  | 
| 1013 1023 | 
             
                        return self._global_variables
         | 
| 1014 1024 |  | 
| 1025 | 
            +
                def get_global_variables_dict(self) -> Dict[VariableMatcher, VariableDefinition]:
         | 
| 1026 | 
            +
                    with self._global_variables_dict_lock:
         | 
| 1027 | 
            +
                        if self._global_variables_dict is None:
         | 
| 1028 | 
            +
                            self._global_variables_dict = {m: v for m, v in self.yield_variables()}
         | 
| 1029 | 
            +
             | 
| 1030 | 
            +
                        return self._global_variables_dict
         | 
| 1031 | 
            +
             | 
| 1015 1032 | 
             
                def yield_variables(
         | 
| 1016 1033 | 
             
                    self,
         | 
| 1017 1034 | 
             
                    nodes: Optional[List[ast.AST]] = None,
         | 
| 1018 1035 | 
             
                    position: Optional[Position] = None,
         | 
| 1019 1036 | 
             
                    skip_commandline_variables: bool = False,
         | 
| 1020 1037 | 
             
                    skip_local_variables: bool = False,
         | 
| 1038 | 
            +
                    skip_global_variables: bool = False,
         | 
| 1021 1039 | 
             
                ) -> Iterator[Tuple[VariableMatcher, VariableDefinition]]:
         | 
| 1022 1040 | 
             
                    yielded: Dict[VariableMatcher, VariableDefinition] = {}
         | 
| 1023 1041 |  | 
| @@ -1053,7 +1071,7 @@ class Namespace: | |
| 1053 1071 | 
             
                                else []
         | 
| 1054 1072 | 
             
                            )
         | 
| 1055 1073 | 
             
                        ],
         | 
| 1056 | 
            -
                        self.get_global_variables(),
         | 
| 1074 | 
            +
                        self.get_global_variables() if not skip_global_variables else [],
         | 
| 1057 1075 | 
             
                    ):
         | 
| 1058 1076 | 
             
                        if var.matcher not in yielded:
         | 
| 1059 1077 | 
             
                            if skip_commandline_variables and isinstance(var, CommandLineVariableDefinition):
         | 
| @@ -1063,17 +1081,7 @@ class Namespace: | |
| 1063 1081 |  | 
| 1064 1082 | 
             
                            yield var.matcher, var
         | 
| 1065 1083 |  | 
| 1066 | 
            -
                def get_suite_variables(
         | 
| 1067 | 
            -
                    self,
         | 
| 1068 | 
            -
                    nodes: Optional[List[ast.AST]] = None,
         | 
| 1069 | 
            -
                    position: Optional[Position] = None,
         | 
| 1070 | 
            -
                ) -> Dict[str, Any]:
         | 
| 1071 | 
            -
                    if nodes:
         | 
| 1072 | 
            -
                        return {
         | 
| 1073 | 
            -
                            v.name: v.value
         | 
| 1074 | 
            -
                            for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
         | 
| 1075 | 
            -
                            if v.has_value
         | 
| 1076 | 
            -
                        }
         | 
| 1084 | 
            +
                def get_suite_variables(self) -> Dict[str, Any]:
         | 
| 1077 1085 | 
             
                    with self._suite_variables_lock:
         | 
| 1078 1086 | 
             
                        vars = {}
         | 
| 1079 1087 |  | 
| @@ -1093,11 +1101,21 @@ class Namespace: | |
| 1093 1101 | 
             
                    nodes: Optional[List[ast.AST]] = None,
         | 
| 1094 1102 | 
             
                    position: Optional[Position] = None,
         | 
| 1095 1103 | 
             
                ) -> Dict[str, Any]:
         | 
| 1096 | 
            -
                     | 
| 1097 | 
            -
                         | 
| 1098 | 
            -
             | 
| 1099 | 
            -
             | 
| 1100 | 
            -
             | 
| 1104 | 
            +
                    if nodes:
         | 
| 1105 | 
            +
                        return {
         | 
| 1106 | 
            +
                            v.name: v.value
         | 
| 1107 | 
            +
                            for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
         | 
| 1108 | 
            +
                            if v.has_value
         | 
| 1109 | 
            +
                        }
         | 
| 1110 | 
            +
             | 
| 1111 | 
            +
                    with self._global_resolvable_variables_lock:
         | 
| 1112 | 
            +
                        if self._global_resolvable_variables is None:
         | 
| 1113 | 
            +
                            self._global_resolvable_variables = {
         | 
| 1114 | 
            +
                                v.name: v.value
         | 
| 1115 | 
            +
                                for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
         | 
| 1116 | 
            +
                                if v.has_value
         | 
| 1117 | 
            +
                            }
         | 
| 1118 | 
            +
                        return self._global_resolvable_variables
         | 
| 1101 1119 |  | 
| 1102 1120 | 
             
                def get_variable_matchers(
         | 
| 1103 1121 | 
             
                    self,
         | 
| @@ -1141,9 +1159,15 @@ class Namespace: | |
| 1141 1159 | 
             
                            position,
         | 
| 1142 1160 | 
             
                            skip_commandline_variables=skip_commandline_variables,
         | 
| 1143 1161 | 
             
                            skip_local_variables=skip_local_variables,
         | 
| 1162 | 
            +
                            skip_global_variables=True,
         | 
| 1144 1163 | 
             
                        ):
         | 
| 1145 1164 | 
             
                            if matcher == m:
         | 
| 1146 1165 | 
             
                                return v
         | 
| 1166 | 
            +
             | 
| 1167 | 
            +
                        result = self.get_global_variables_dict().get(matcher, None)
         | 
| 1168 | 
            +
                        if matcher is not None:
         | 
| 1169 | 
            +
                            return result
         | 
| 1170 | 
            +
             | 
| 1147 1171 | 
             
                    except InvalidVariableError:
         | 
| 1148 1172 | 
             
                        if not ignore_error:
         | 
| 1149 1173 | 
             
                            raise
         | 
| @@ -1376,12 +1400,12 @@ class Namespace: | |
| 1376 1400 | 
             
                    source: Optional[str] = None,
         | 
| 1377 1401 | 
             
                    parent_import: Optional[Import] = None,
         | 
| 1378 1402 | 
             
                    parent_source: Optional[str] = None,
         | 
| 1379 | 
            -
                    depth: int = 0,
         | 
| 1380 1403 | 
             
                ) -> Optional[Dict[str, Any]]:
         | 
| 1381 1404 |  | 
| 1382 | 
            -
                     | 
| 1383 | 
            -
             | 
| 1384 | 
            -
             | 
| 1405 | 
            +
                    with self._logger.measure_time(
         | 
| 1406 | 
            +
                        lambda: f"loading imports for {self.source if top_level else source}",
         | 
| 1407 | 
            +
                        context_name="import",
         | 
| 1408 | 
            +
                    ):
         | 
| 1385 1409 | 
             
                        for imp in imports:
         | 
| 1386 1410 | 
             
                            if variables is None:
         | 
| 1387 1411 | 
             
                                variables = self.get_suite_variables()
         | 
| @@ -1418,7 +1442,6 @@ class Namespace: | |
| 1418 1442 | 
             
                                                source=entry.library_doc.source,
         | 
| 1419 1443 | 
             
                                                parent_import=imp if top_level else parent_import,
         | 
| 1420 1444 | 
             
                                                parent_source=parent_source if top_level else source,
         | 
| 1421 | 
            -
                                                depth=depth + 1,
         | 
| 1422 1445 | 
             
                                            )
         | 
| 1423 1446 | 
             
                                        except (SystemExit, KeyboardInterrupt):
         | 
| 1424 1447 | 
             
                                            raise
         | 
| @@ -1568,48 +1591,40 @@ class Namespace: | |
| 1568 1591 | 
             
                                            code=Error.LIBRARY_ALREADY_IMPORTED,
         | 
| 1569 1592 | 
             
                                        )
         | 
| 1570 1593 |  | 
| 1571 | 
            -
                    finally:
         | 
| 1572 | 
            -
                        self._logger.debug(
         | 
| 1573 | 
            -
                            lambda: f"{'  '*depth}end imports for "
         | 
| 1574 | 
            -
                            f"{self.document if top_level else source} in {time.monotonic() - current_time}s"
         | 
| 1575 | 
            -
                        )
         | 
| 1576 | 
            -
             | 
| 1577 1594 | 
             
                    return variables
         | 
| 1578 1595 |  | 
| 1596 | 
            +
                def _import_lib(self, library: str, variables: Optional[Dict[str, Any]] = None) -> Optional[LibraryEntry]:
         | 
| 1597 | 
            +
                    try:
         | 
| 1598 | 
            +
                        return self._get_library_entry(
         | 
| 1599 | 
            +
                            library,
         | 
| 1600 | 
            +
                            (),
         | 
| 1601 | 
            +
                            None,
         | 
| 1602 | 
            +
                            str(Path(self.source).parent),
         | 
| 1603 | 
            +
                            is_default_library=True,
         | 
| 1604 | 
            +
                            variables=variables,
         | 
| 1605 | 
            +
                        )
         | 
| 1606 | 
            +
                    except (SystemExit, KeyboardInterrupt):
         | 
| 1607 | 
            +
                        raise
         | 
| 1608 | 
            +
                    except BaseException as e:
         | 
| 1609 | 
            +
                        self.append_diagnostics(
         | 
| 1610 | 
            +
                            range=Range.zero(),
         | 
| 1611 | 
            +
                            message=f"Can't import default library '{library}': {str(e) or type(e).__name__}",
         | 
| 1612 | 
            +
                            severity=DiagnosticSeverity.ERROR,
         | 
| 1613 | 
            +
                            source="Robot",
         | 
| 1614 | 
            +
                            code=type(e).__qualname__,
         | 
| 1615 | 
            +
                        )
         | 
| 1616 | 
            +
                        return None
         | 
| 1617 | 
            +
             | 
| 1579 1618 | 
             
                def _import_default_libraries(self, variables: Optional[Dict[str, Any]] = None) -> None:
         | 
| 1580 | 
            -
                    def _import_lib(library: str, variables: Optional[Dict[str, Any]] = None) -> Optional[LibraryEntry]:
         | 
| 1581 | 
            -
                        try:
         | 
| 1582 | 
            -
                            return self._get_library_entry(
         | 
| 1583 | 
            -
                                library,
         | 
| 1584 | 
            -
                                (),
         | 
| 1585 | 
            -
                                None,
         | 
| 1586 | 
            -
                                str(Path(self.source).parent),
         | 
| 1587 | 
            -
                                is_default_library=True,
         | 
| 1588 | 
            -
                                variables=variables,
         | 
| 1589 | 
            -
                            )
         | 
| 1590 | 
            -
                        except (SystemExit, KeyboardInterrupt):
         | 
| 1591 | 
            -
                            raise
         | 
| 1592 | 
            -
                        except BaseException as e:
         | 
| 1593 | 
            -
                            self.append_diagnostics(
         | 
| 1594 | 
            -
                                range=Range.zero(),
         | 
| 1595 | 
            -
                                message=f"Can't import default library '{library}': {str(e) or type(e).__name__}",
         | 
| 1596 | 
            -
                                severity=DiagnosticSeverity.ERROR,
         | 
| 1597 | 
            -
                                source="Robot",
         | 
| 1598 | 
            -
                                code=type(e).__qualname__,
         | 
| 1599 | 
            -
                            )
         | 
| 1600 | 
            -
                            return None
         | 
| 1601 1619 |  | 
| 1602 | 
            -
                    self._logger. | 
| 1603 | 
            -
                    try:
         | 
| 1620 | 
            +
                    with self._logger.measure_time(lambda: f"importing default libraries for {self.source}", context_name="import"):
         | 
| 1604 1621 | 
             
                        if variables is None:
         | 
| 1605 1622 | 
             
                            variables = self.get_suite_variables()
         | 
| 1606 1623 |  | 
| 1607 1624 | 
             
                        for library in DEFAULT_LIBRARIES:
         | 
| 1608 | 
            -
                            e = _import_lib(library, variables)
         | 
| 1625 | 
            +
                            e = self._import_lib(library, variables)
         | 
| 1609 1626 | 
             
                            if e is not None:
         | 
| 1610 1627 | 
             
                                self._libraries[e.alias or e.name or e.import_name] = e
         | 
| 1611 | 
            -
                    finally:
         | 
| 1612 | 
            -
                        self._logger.debug(lambda: f"end import default libraries for document {self.document}")
         | 
| 1613 1628 |  | 
| 1614 1629 | 
             
                @_logger.call
         | 
| 1615 1630 | 
             
                def _get_library_entry(
         | 
| @@ -1820,8 +1835,6 @@ class Namespace: | |
| 1820 1835 |  | 
| 1821 1836 | 
             
                @_logger.call(condition=lambda self: not self._analyzed)
         | 
| 1822 1837 | 
             
                def analyze(self) -> None:
         | 
| 1823 | 
            -
                    import time
         | 
| 1824 | 
            -
             | 
| 1825 1838 | 
             
                    from .namespace_analyzer import NamespaceAnalyzer
         | 
| 1826 1839 |  | 
| 1827 1840 | 
             
                    with self._analyze_lock:
         | 
| @@ -1830,53 +1843,43 @@ class Namespace: | |
| 1830 1843 |  | 
| 1831 1844 | 
             
                            self.ensure_initialized()
         | 
| 1832 1845 |  | 
| 1833 | 
            -
                            self._logger. | 
| 1834 | 
            -
             | 
| 1835 | 
            -
             | 
| 1836 | 
            -
                            try:
         | 
| 1837 | 
            -
                                result = NamespaceAnalyzer(self.model, self, self.create_finder()).run()
         | 
| 1846 | 
            +
                            with self._logger.measure_time(lambda: f"analyzing document {self.source}", context_name="analyze"):
         | 
| 1847 | 
            +
                                try:
         | 
| 1848 | 
            +
                                    result = NamespaceAnalyzer(self.model, self, self.create_finder()).run()
         | 
| 1838 1849 |  | 
| 1839 | 
            -
             | 
| 1840 | 
            -
             | 
| 1841 | 
            -
             | 
| 1842 | 
            -
             | 
| 1843 | 
            -
             | 
| 1850 | 
            +
                                    self._diagnostics += result.diagnostics
         | 
| 1851 | 
            +
                                    self._keyword_references = result.keyword_references
         | 
| 1852 | 
            +
                                    self._variable_references = result.variable_references
         | 
| 1853 | 
            +
                                    self._local_variable_assignments = result.local_variable_assignments
         | 
| 1854 | 
            +
                                    self._namespace_references = result.namespace_references
         | 
| 1844 1855 |  | 
| 1845 | 
            -
             | 
| 1856 | 
            +
                                    lib_doc = self.get_library_doc()
         | 
| 1846 1857 |  | 
| 1847 | 
            -
             | 
| 1848 | 
            -
             | 
| 1849 | 
            -
             | 
| 1850 | 
            -
             | 
| 1851 | 
            -
             | 
| 1852 | 
            -
             | 
| 1853 | 
            -
             | 
| 1854 | 
            -
             | 
| 1855 | 
            -
             | 
| 1856 | 
            -
             | 
| 1857 | 
            -
             | 
| 1858 | 
            +
                                    if lib_doc.errors is not None:
         | 
| 1859 | 
            +
                                        for err in lib_doc.errors:
         | 
| 1860 | 
            +
                                            self.append_diagnostics(
         | 
| 1861 | 
            +
                                                range=Range(
         | 
| 1862 | 
            +
                                                    start=Position(
         | 
| 1863 | 
            +
                                                        line=((err.line_no - 1) if err.line_no is not None else 0),
         | 
| 1864 | 
            +
                                                        character=0,
         | 
| 1865 | 
            +
                                                    ),
         | 
| 1866 | 
            +
                                                    end=Position(
         | 
| 1867 | 
            +
                                                        line=((err.line_no - 1) if err.line_no is not None else 0),
         | 
| 1868 | 
            +
                                                        character=0,
         | 
| 1869 | 
            +
                                                    ),
         | 
| 1858 1870 | 
             
                                                ),
         | 
| 1859 | 
            -
             | 
| 1860 | 
            -
             | 
| 1861 | 
            -
             | 
| 1862 | 
            -
             | 
| 1863 | 
            -
                                             | 
| 1864 | 
            -
             | 
| 1865 | 
            -
             | 
| 1866 | 
            -
             | 
| 1867 | 
            -
             | 
| 1868 | 
            -
             | 
| 1869 | 
            -
                                 | 
| 1870 | 
            -
             | 
| 1871 | 
            -
                                self._analyzed = not canceled
         | 
| 1872 | 
            -
             | 
| 1873 | 
            -
                                self._logger.debug(
         | 
| 1874 | 
            -
                                    lambda: (
         | 
| 1875 | 
            -
                                        f"end analyzed {self.document} succeed in {time.monotonic() - start_time}s"
         | 
| 1876 | 
            -
                                        if self._analyzed
         | 
| 1877 | 
            -
                                        else f"end analyzed {self.document} failed in {time.monotonic() - start_time}s"
         | 
| 1878 | 
            -
                                    )
         | 
| 1879 | 
            -
                                )
         | 
| 1871 | 
            +
                                                message=err.message,
         | 
| 1872 | 
            +
                                                severity=DiagnosticSeverity.ERROR,
         | 
| 1873 | 
            +
                                                source=DIAGNOSTICS_SOURCE_NAME,
         | 
| 1874 | 
            +
                                                code=err.type_name,
         | 
| 1875 | 
            +
                                            )
         | 
| 1876 | 
            +
                                # TODO: implement CancelationToken
         | 
| 1877 | 
            +
                                except CancelledError:
         | 
| 1878 | 
            +
                                    canceled = True
         | 
| 1879 | 
            +
                                    self._logger.debug("analyzing canceled")
         | 
| 1880 | 
            +
                                    raise
         | 
| 1881 | 
            +
                                finally:
         | 
| 1882 | 
            +
                                    self._analyzed = not canceled
         | 
| 1880 1883 |  | 
| 1881 1884 | 
             
                            self.has_analysed(self)
         | 
| 1882 1885 |  | 
| @@ -55,3 +55,20 @@ class CacheConfig(ConfigBase): | |
| 55 55 | 
             
            @dataclass
         | 
| 56 56 | 
             
            class AnalysisRobotConfig(ConfigBase):
         | 
| 57 57 | 
             
                global_library_search_order: List[str] = field(default_factory=list)
         | 
| 58 | 
            +
             | 
| 59 | 
            +
             | 
| 60 | 
            +
            @config_section("robotcode.analysis.diagnosticModifiers")
         | 
| 61 | 
            +
            @dataclass
         | 
| 62 | 
            +
            class AnalysisDiagnosticModifiersConfig(ConfigBase):
         | 
| 63 | 
            +
                ignore: List[str] = field(default_factory=list)
         | 
| 64 | 
            +
                error: List[str] = field(default_factory=list)
         | 
| 65 | 
            +
                warning: List[str] = field(default_factory=list)
         | 
| 66 | 
            +
                information: List[str] = field(default_factory=list)
         | 
| 67 | 
            +
                hint: List[str] = field(default_factory=list)
         | 
| 68 | 
            +
             | 
| 69 | 
            +
             | 
| 70 | 
            +
            @dataclass
         | 
| 71 | 
            +
            class WorkspaceAnalysisConfig:
         | 
| 72 | 
            +
                cache: CacheConfig = field(default_factory=CacheConfig)
         | 
| 73 | 
            +
                robot: AnalysisRobotConfig = field(default_factory=AnalysisRobotConfig)
         | 
| 74 | 
            +
                modifiers: AnalysisDiagnosticModifiersConfig = field(default_factory=AnalysisDiagnosticModifiersConfig)
         | 
    
        robotcode/robot/utils/ast.py
    CHANGED
    
    | @@ -2,7 +2,9 @@ from __future__ import annotations | |
| 2 2 |  | 
| 3 3 | 
             
            import ast
         | 
| 4 4 | 
             
            import itertools
         | 
| 5 | 
            -
            from typing import Any, Iterator, List, Optional, Sequence, Set, Tuple
         | 
| 5 | 
            +
            from typing import Any, Dict, Iterator, List, Optional, Sequence, Set, Tuple, Type, TypeVar, Union
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from typing_extensions import TypeGuard
         | 
| 6 8 |  | 
| 7 9 | 
             
            from robot.errors import VariableError
         | 
| 8 10 | 
             
            from robot.parsing.lexer.tokens import Token
         | 
| @@ -17,17 +19,42 @@ if get_robot_version() < (7, 0): | |
| 17 19 | 
             
            else:
         | 
| 18 20 | 
             
                from robot.variables.search import VariableMatches as VariableIterator
         | 
| 19 21 |  | 
| 22 | 
            +
            _cached_isinstance_cache: Dict[Tuple[type, Tuple[type, ...]], bool] = {}
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            _T = TypeVar("_T")
         | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            def cached_isinstance(obj: Any, *expected_types: Type[_T]) -> TypeGuard[Union[_T]]:
         | 
| 28 | 
            +
                try:
         | 
| 29 | 
            +
                    t = type(obj)
         | 
| 30 | 
            +
                    if (t, expected_types) in _cached_isinstance_cache:
         | 
| 31 | 
            +
                        return _cached_isinstance_cache[(t, expected_types)]
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    _cached_isinstance_cache[(t, expected_types)] = result = isinstance(obj, expected_types)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    return result
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                except TypeError:
         | 
| 38 | 
            +
                    return False
         | 
| 39 | 
            +
             | 
| 40 | 
            +
             | 
| 41 | 
            +
            # def cached_isinstance(obj: Any, *expected_types: type) -> bool:
         | 
| 42 | 
            +
            #     try:
         | 
| 43 | 
            +
            #         return isinstance(obj, expected_types)
         | 
| 44 | 
            +
            #     except TypeError:
         | 
| 45 | 
            +
            #         return False
         | 
| 46 | 
            +
             | 
| 20 47 |  | 
| 21 48 | 
             
            def iter_nodes(node: ast.AST, descendants: bool = True) -> Iterator[ast.AST]:
         | 
| 22 49 | 
             
                for _field, value in ast.iter_fields(node):
         | 
| 23 | 
            -
                    if  | 
| 50 | 
            +
                    if cached_isinstance(value, list):
         | 
| 24 51 | 
             
                        for item in value:
         | 
| 25 | 
            -
                            if  | 
| 52 | 
            +
                            if cached_isinstance(item, ast.AST):
         | 
| 26 53 | 
             
                                yield item
         | 
| 27 54 | 
             
                                if descendants:
         | 
| 28 55 | 
             
                                    yield from iter_nodes(item)
         | 
| 29 56 |  | 
| 30 | 
            -
                    elif  | 
| 57 | 
            +
                    elif cached_isinstance(value, ast.AST):
         | 
| 31 58 | 
             
                        yield value
         | 
| 32 59 | 
             
                        if descendants:
         | 
| 33 60 | 
             
                            yield from iter_nodes(value)
         | 
| @@ -53,7 +80,7 @@ class FirstAndLastRealStatementFinder(Visitor): | |
| 53 80 | 
             
                    return finder.first_statement, finder.last_statement
         | 
| 54 81 |  | 
| 55 82 | 
             
                def visit_Statement(self, statement: ast.AST) -> None:  # noqa: N802
         | 
| 56 | 
            -
                    if not  | 
| 83 | 
            +
                    if not cached_isinstance(statement, EmptyLine):
         | 
| 57 84 | 
             
                        if self.first_statement is None:
         | 
| 58 85 | 
             
                            self.first_statement = statement
         | 
| 59 86 |  | 
| @@ -63,7 +90,7 @@ class FirstAndLastRealStatementFinder(Visitor): | |
| 63 90 | 
             
            def _get_non_data_range_from_node(
         | 
| 64 91 | 
             
                node: ast.AST, only_start: bool = False, allow_comments: bool = False
         | 
| 65 92 | 
             
            ) -> Optional[Range]:
         | 
| 66 | 
            -
                if  | 
| 93 | 
            +
                if cached_isinstance(node, Statement) and node.tokens:
         | 
| 67 94 | 
             
                    start_token = next(
         | 
| 68 95 | 
             
                        (
         | 
| 69 96 | 
             
                            v
         | 
| @@ -115,7 +142,7 @@ def range_from_node( | |
| 115 142 | 
             
                allow_comments: bool = False,
         | 
| 116 143 | 
             
            ) -> Range:
         | 
| 117 144 | 
             
                if skip_non_data:
         | 
| 118 | 
            -
                    if  | 
| 145 | 
            +
                    if cached_isinstance(node, Statement) and node.tokens:
         | 
| 119 146 | 
             
                        result = _get_non_data_range_from_node(node, only_start, allow_comments)
         | 
| 120 147 | 
             
                        if result is not None:
         | 
| 121 148 | 
             
                            return result
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.3
         | 
| 2 2 | 
             
            Name: robotcode-robot
         | 
| 3 | 
            -
            Version: 0. | 
| 3 | 
            +
            Version: 0.93.0
         | 
| 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://opencollective.com/robotcode
         | 
| @@ -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. | 
| 29 | 
            +
            Requires-Dist: robotcode-core==0.93.0
         | 
| 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
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            robotcode/robot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 2 | 
            +
            robotcode/robot/__version__.py,sha256=W-KEJT0wpRrG8XJ2aDG4NSyzaUucgZR9y6mwfCTlku4,23
         | 
| 3 | 
            +
            robotcode/robot/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
         | 
| 4 | 
            +
            robotcode/robot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 5 | 
            +
            robotcode/robot/config/loader.py,sha256=bNJwr_XdCoUzpG2ag0BH33PIfiCwn0GMxn7q_Sw3zOk,8103
         | 
| 6 | 
            +
            robotcode/robot/config/model.py,sha256=sgr6-4_E06g-yIXW41Z-NtIXZ_7JMmR5WvUD7kTUqu4,89106
         | 
| 7 | 
            +
            robotcode/robot/config/utils.py,sha256=xY-LH31BidWzonpvSrle-4HvKrp02I7IRqU2JwlL4Ls,2931
         | 
| 8 | 
            +
            robotcode/robot/diagnostics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 9 | 
            +
            robotcode/robot/diagnostics/diagnostics_modifier.py,sha256=3dDsu8-ET6weIvv7Sk3IQaPYFNxnXUs8Y7gpGTjfOBs,9796
         | 
| 10 | 
            +
            robotcode/robot/diagnostics/document_cache_helper.py,sha256=MlOPXC3mUVjNB2rHn5UJK7NnUPa8S4mE3qojILOi_Mk,23756
         | 
| 11 | 
            +
            robotcode/robot/diagnostics/entities.py,sha256=dWZFSrAuW9wzW9AEDSr-stseexLbJIYfdScfAbBj4FY,11002
         | 
| 12 | 
            +
            robotcode/robot/diagnostics/errors.py,sha256=HCE0h0_ui1tx-6pJHs0r4s09ZHmArYwKUo-_lBl9K-4,1600
         | 
| 13 | 
            +
            robotcode/robot/diagnostics/imports_manager.py,sha256=GvcIEqghVjtliTWUwQo4N-xier00CGnEh_eO7l05cJg,57187
         | 
| 14 | 
            +
            robotcode/robot/diagnostics/library_doc.py,sha256=7m29COvY_YlK_n9dj57q0c7sFRThoR_X4bgdZapWwaY,98160
         | 
| 15 | 
            +
            robotcode/robot/diagnostics/model_helper.py,sha256=_5ixKKMrb-nY-uvV8_WjJ1rlNlz7gT7kHM5NYi_hjVg,30232
         | 
| 16 | 
            +
            robotcode/robot/diagnostics/namespace.py,sha256=lH5RReu-fW0g8CZBh9LKWHItCZh14D-XFvFdYUvBoDg,90151
         | 
| 17 | 
            +
            robotcode/robot/diagnostics/namespace_analyzer.py,sha256=3eC1xEBm_foCnqoHk8Cj6O11UXOHcHxWnfuKP8M5KIQ,51369
         | 
| 18 | 
            +
            robotcode/robot/diagnostics/workspace_config.py,sha256=3SoewUj_LZB1Ki5hXM8oxQpJr6vyiog66SUw-ibODSA,2478
         | 
| 19 | 
            +
            robotcode/robot/utils/__init__.py,sha256=OjNPMn_XSnfaMCyKd8Kmq6vlRt6mIGlzW4qiiD3ykUg,447
         | 
| 20 | 
            +
            robotcode/robot/utils/ast.py,sha256=_ob36KHFY776n9dhljn0xAWVoUDb7pV86fPW40vIirY,11266
         | 
| 21 | 
            +
            robotcode/robot/utils/markdownformatter.py,sha256=0XZZ5wDU2yfzIuShjG7h79PgzMaQJ501WH4YRFcG1VM,11615
         | 
| 22 | 
            +
            robotcode/robot/utils/match.py,sha256=ofyfXgrvVddl7a064Dk5Kiqp3a-n_6gTIgqDbL3E80Q,632
         | 
| 23 | 
            +
            robotcode/robot/utils/robot_path.py,sha256=qKBh1cEnReBBLKkWu4gB9EzM-scAwE4xJc1m6v2LRN0,1786
         | 
| 24 | 
            +
            robotcode/robot/utils/stubs.py,sha256=6-DMI_CQVJHDgG13t-zINKGCRb_Q7MQPm0_AkfhAEvE,748
         | 
| 25 | 
            +
            robotcode/robot/utils/variables.py,sha256=fEl8S37lb_mD4hn2MZRAlkiuLGBjAOeZVK0r2o2CfPw,742
         | 
| 26 | 
            +
            robotcode/robot/utils/visitor.py,sha256=uYLqEhGPmzWKWI3SSrmCaYMwtKvNShvbiPZ4b3FavX8,3241
         | 
| 27 | 
            +
            robotcode_robot-0.93.0.dist-info/METADATA,sha256=64V1dXSzlmT6KArsIP0YqCm79s_oPXVm3MXBlenwx2E,2240
         | 
| 28 | 
            +
            robotcode_robot-0.93.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
         | 
| 29 | 
            +
            robotcode_robot-0.93.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
         | 
| 30 | 
            +
            robotcode_robot-0.93.0.dist-info/RECORD,,
         | 
| @@ -1,30 +0,0 @@ | |
| 1 | 
            -
            robotcode/robot/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 2 | 
            -
            robotcode/robot/__version__.py,sha256=RBon26SFk4Bs08h0XAmTYW8lrYs3N9ihifF9r6VT4Vc,23
         | 
| 3 | 
            -
            robotcode/robot/py.typed,sha256=bWew9mHgMy8LqMu7RuqQXFXLBxh2CRx0dUbSx-3wE48,27
         | 
| 4 | 
            -
            robotcode/robot/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 5 | 
            -
            robotcode/robot/config/loader.py,sha256=LpGqJAdysvVSZpccW-Il52xn9RMBBb9X94emlBY7zCc,6077
         | 
| 6 | 
            -
            robotcode/robot/config/model.py,sha256=w2qqxPwuv-N3GEZsCaaxFxU5iPfQr3oS1mqMkZFkRPU,88891
         | 
| 7 | 
            -
            robotcode/robot/config/utils.py,sha256=c_WZg39DJgM6kXcAH_h-v68qhf1eStJ0TslTawaJoZw,2827
         | 
| 8 | 
            -
            robotcode/robot/diagnostics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 9 | 
            -
            robotcode/robot/diagnostics/diagnostics_modifier.py,sha256=9AFptQsdw_TvgBkKqutpvI8WKsOUXipXQDOExarJJy4,6903
         | 
| 10 | 
            -
            robotcode/robot/diagnostics/document_cache_helper.py,sha256=pa9AdSbEFZJ6VSdZluGyfzyZPjzBfNFAv5pXJEM-7fc,22664
         | 
| 11 | 
            -
            robotcode/robot/diagnostics/entities.py,sha256=AtrqPAS3XUC-8VpFmqMXfMKjQHmfxXZlyGWWFaEBpQA,10979
         | 
| 12 | 
            -
            robotcode/robot/diagnostics/errors.py,sha256=HCE0h0_ui1tx-6pJHs0r4s09ZHmArYwKUo-_lBl9K-4,1600
         | 
| 13 | 
            -
            robotcode/robot/diagnostics/imports_manager.py,sha256=qE__lm0Hsj3R0gUauXRmbWJPYihNjk3O-c5hcICGQjc,56251
         | 
| 14 | 
            -
            robotcode/robot/diagnostics/library_doc.py,sha256=CHgyC9GMRQFP3fGTxWa139rIcGIk8Ys6Q_ZIDSgse7k,97324
         | 
| 15 | 
            -
            robotcode/robot/diagnostics/model_helper.py,sha256=_5ixKKMrb-nY-uvV8_WjJ1rlNlz7gT7kHM5NYi_hjVg,30232
         | 
| 16 | 
            -
            robotcode/robot/diagnostics/namespace.py,sha256=jCUb5GmMDA6KTr2BnwHD_0Mp_gTg1XGskUvRYPL7XQ0,89543
         | 
| 17 | 
            -
            robotcode/robot/diagnostics/namespace_analyzer.py,sha256=3eC1xEBm_foCnqoHk8Cj6O11UXOHcHxWnfuKP8M5KIQ,51369
         | 
| 18 | 
            -
            robotcode/robot/diagnostics/workspace_config.py,sha256=lWNq1KmGGJ9cHFNHn0QTCBHHzgz4AewTw0l-W4TKrj0,1803
         | 
| 19 | 
            -
            robotcode/robot/utils/__init__.py,sha256=OjNPMn_XSnfaMCyKd8Kmq6vlRt6mIGlzW4qiiD3ykUg,447
         | 
| 20 | 
            -
            robotcode/robot/utils/ast.py,sha256=ynxvXv1SHkAcF07m76ey9_zaGCYXhlPOnny7km-XWSQ,10479
         | 
| 21 | 
            -
            robotcode/robot/utils/markdownformatter.py,sha256=0XZZ5wDU2yfzIuShjG7h79PgzMaQJ501WH4YRFcG1VM,11615
         | 
| 22 | 
            -
            robotcode/robot/utils/match.py,sha256=ofyfXgrvVddl7a064Dk5Kiqp3a-n_6gTIgqDbL3E80Q,632
         | 
| 23 | 
            -
            robotcode/robot/utils/robot_path.py,sha256=qKBh1cEnReBBLKkWu4gB9EzM-scAwE4xJc1m6v2LRN0,1786
         | 
| 24 | 
            -
            robotcode/robot/utils/stubs.py,sha256=6-DMI_CQVJHDgG13t-zINKGCRb_Q7MQPm0_AkfhAEvE,748
         | 
| 25 | 
            -
            robotcode/robot/utils/variables.py,sha256=fEl8S37lb_mD4hn2MZRAlkiuLGBjAOeZVK0r2o2CfPw,742
         | 
| 26 | 
            -
            robotcode/robot/utils/visitor.py,sha256=uYLqEhGPmzWKWI3SSrmCaYMwtKvNShvbiPZ4b3FavX8,3241
         | 
| 27 | 
            -
            robotcode_robot-0.91.0.dist-info/METADATA,sha256=Cl7XlzEEn_Q5xmyv7C6R09JliQm1pL45DGuC-M4cSrY,2240
         | 
| 28 | 
            -
            robotcode_robot-0.91.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
         | 
| 29 | 
            -
            robotcode_robot-0.91.0.dist-info/licenses/LICENSE.txt,sha256=B05uMshqTA74s-0ltyHKI6yoPfJ3zYgQbvcXfDVGFf8,10280
         | 
| 30 | 
            -
            robotcode_robot-0.91.0.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         |