Skip to content

Commit c828202

Browse files
committed
refactor(debugger): split get_variables method and splitup version specific behavior for exception handling
1 parent 4c6b9af commit c828202

File tree

1 file changed

+146
-127
lines changed

1 file changed

+146
-127
lines changed

packages/debugger/src/robotcode/debugger/debugger.py

Lines changed: 146 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
)
7373
from .id_manager import IdManager
7474

75+
if get_robot_version() >= (5, 0):
76+
from robot.running.model import Try
77+
from robot.utils import Matcher as RobotMatcher
78+
7579
if get_robot_version() >= (7, 0):
7680
from robot.running import UserKeyword as UserKeywordHandler
7781
else:
@@ -1202,12 +1206,8 @@ def _get_matcher(self, pattern_type: str) -> Optional[Callable[[str, str], bool]
12021206

12031207
def _glob_matcher(self, message: str, pattern: str) -> bool:
12041208
"""Optimized glob matcher with cached Robot Matcher."""
1205-
if self.__robot_matcher is None:
1206-
from robot.utils import Matcher
1207-
1208-
self.__robot_matcher = Matcher
12091209

1210-
return bool(self.__robot_matcher(pattern, spaceless=False, caseless=False).match(message))
1210+
return bool(RobotMatcher(pattern, spaceless=False, caseless=False).match(message))
12111211

12121212
def _regexp_matcher(self, message: str, pattern: str) -> bool:
12131213
"""Optimized regex matcher with LRU caching (max 25 entries)."""
@@ -1259,14 +1259,21 @@ def _get_step_data(self, step: Any) -> Any:
12591259
def _get_step_data(self, step: Any) -> Any:
12601260
return step.data
12611261

1262-
def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1263-
if not message:
1264-
return True
1262+
if get_robot_version() < (5, 0):
1263+
1264+
def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1265+
if not message:
1266+
return True
1267+
return False
1268+
else:
12651269

1266-
if self.debug_logger:
1267-
if get_robot_version() >= (5, 0):
1268-
from robot.running.model import Try
1270+
def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1271+
if not message:
1272+
return True
12691273

1274+
# TODO resolve variables in exception message
1275+
1276+
if self.debug_logger:
12701277
if self.debug_logger.steps:
12711278
for branch in [
12721279
self._get_step_data(f)
@@ -1276,7 +1283,7 @@ def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
12761283
for except_branch in branch.except_branches:
12771284
if self._should_run_except(except_branch, message):
12781285
return False
1279-
return True
1286+
return True
12801287

12811288
def end_keyword(self, name: str, attributes: AttributeDict) -> None:
12821289
if self.state == State.CallKeyword:
@@ -1610,131 +1617,143 @@ def get_variables(
16101617
count: Optional[int] = None,
16111618
format: Optional[ValueFormat] = None,
16121619
) -> List[Variable]:
1613-
result: MutableMapping[str, Any] = {}
1614-
16151620
if filter is None:
1616-
entry = next(
1617-
(
1618-
v
1619-
for v in self.stack_frames
1620-
if variables_reference in [v.global_id, v.suite_id, v.test_id, v.local_id]
1621-
),
1622-
None,
1623-
)
1624-
if entry is not None:
1625-
context = entry.context()
1626-
if context is not None:
1627-
if entry.global_id == variables_reference:
1628-
result.update(
1629-
{k: self._create_variable(k, v) for k, v in context.variables._global.as_dict().items()}
1630-
)
1631-
elif entry.suite_id == variables_reference:
1632-
globals = context.variables._global.as_dict()
1633-
vars = entry.get_first_or_self().variables()
1634-
vars_dict = vars.as_dict() if vars is not None else {}
1635-
result.update(
1636-
{
1637-
k: self._create_variable(k, v)
1638-
for k, v in context.variables._suite.as_dict().items()
1639-
if (k not in globals or globals[k] != v) and (k in vars_dict)
1640-
}
1641-
)
1642-
elif entry.test_id == variables_reference:
1643-
globals = context.variables._suite.as_dict()
1644-
vars = entry.get_first_or_self().variables()
1645-
vars_dict = vars.as_dict() if vars is not None else {}
1646-
result.update(
1647-
{
1648-
k: self._create_variable(k, v)
1649-
for k, v in context.variables._test.as_dict().items()
1650-
if (k not in globals or globals[k] != v) and (k in vars_dict)
1651-
}
1652-
)
1653-
elif entry.local_id == variables_reference:
1654-
vars = entry.get_first_or_self().variables()
1655-
1656-
if self._current_exception is not None:
1657-
result["${EXCEPTION}"] = self._create_variable(
1658-
"${EXCEPTION}",
1659-
self._current_exception,
1660-
VariablePresentationHint(kind="virtual"),
1661-
)
1662-
1663-
if vars is not None:
1664-
p = entry.parent() if entry.parent else None
1665-
1666-
globals = (
1667-
(p.get_first_or_self().variables() if p is not None else None)
1668-
or context.variables._test
1669-
or context.variables._suite
1670-
or context.variables._global
1671-
).as_dict()
1672-
1673-
suite_vars = (context.variables._suite or context.variables._global).as_dict()
1674-
1675-
result.update(
1676-
{
1677-
k: self._create_variable(k, v)
1678-
for k, v in vars.as_dict().items()
1679-
if (k not in globals or globals[k] != v)
1680-
and (entry.handler is None or k not in suite_vars or suite_vars[k] != v)
1681-
}
1682-
)
1683-
1684-
if entry.handler is not None and self.get_handler_args(entry.handler):
1685-
for argument in self.get_handler_args(entry.handler).argument_names:
1686-
name = f"${{{argument}}}"
1687-
try:
1688-
value = vars[name]
1689-
except (SystemExit, KeyboardInterrupt):
1690-
raise
1691-
except BaseException as e:
1692-
value = str(e)
1693-
1694-
result[name] = self._create_variable(name, value)
1695-
else:
1696-
value = self._variables_cache.get(variables_reference, None)
1621+
return self._get_variables_no_filter(variables_reference)
1622+
if filter == "indexed":
1623+
return self._get_variables_indexed(variables_reference, start, count)
1624+
if filter == "named":
1625+
return self._get_variables_named(variables_reference, start, count)
16971626

1698-
if value is not None and isinstance(value, Mapping):
1699-
result.update({"len()": self._create_variable("len()", len(value))})
1627+
raise ValueError(f"Unknown filter: {filter}")
17001628

1701-
for i, (k, v) in enumerate(value.items(), start or 0):
1702-
result[repr(i)] = self._create_variable(repr(k), v)
1703-
if i >= MAX_VARIABLE_ITEMS_DISPLAY:
1704-
result["Unable to handle"] = self._create_variable(
1705-
"Unable to handle",
1706-
f"Maximum number of items ({MAX_VARIABLE_ITEMS_DISPLAY}) reached.",
1707-
)
1708-
break
1709-
1710-
elif value is not None and isinstance(value, Sequence) and not isinstance(value, str):
1711-
result.update({"len()": self._create_variable("len()", len(value))})
1712-
1713-
elif filter == "indexed":
1629+
def _get_variables_no_filter(self, variables_reference: int) -> List[Variable]:
1630+
result: MutableMapping[str, Any] = {}
1631+
entry = next(
1632+
(v for v in self.stack_frames if variables_reference in [v.global_id, v.suite_id, v.test_id, v.local_id]),
1633+
None,
1634+
)
1635+
if entry is not None:
1636+
context = entry.context()
1637+
if context is not None:
1638+
if entry.global_id == variables_reference:
1639+
result.update(
1640+
{k: self._create_variable(k, v) for k, v in context.variables._global.as_dict().items()}
1641+
)
1642+
elif entry.suite_id == variables_reference:
1643+
result.update(self._get_suite_variables(context, entry))
1644+
elif entry.test_id == variables_reference:
1645+
result.update(self._get_test_variables(context, entry))
1646+
elif entry.local_id == variables_reference:
1647+
result.update(self._get_local_variables(context, entry))
1648+
else:
17141649
value = self._variables_cache.get(variables_reference, None)
1650+
result.update(self._get_cached_variables(value))
1651+
return list(result.values())
17151652

1716-
if value is not None:
1717-
c = 0
1653+
def _get_suite_variables(self, context: Any, entry: Any) -> MutableMapping[str, Variable]:
1654+
result: MutableMapping[str, Variable] = {}
1655+
globals = context.variables._global.as_dict()
1656+
vars = entry.get_first_or_self().variables()
1657+
vars_dict = vars.as_dict() if vars is not None else {}
1658+
for k, v in context.variables._suite.as_dict().items():
1659+
if (k not in globals or globals[k] != v) and (k in vars_dict):
1660+
result[k] = self._create_variable(k, v)
1661+
return result
17181662

1719-
padding = len(str(len(value)))
1663+
def _get_test_variables(self, context: Any, entry: Any) -> MutableMapping[str, Variable]:
1664+
result: MutableMapping[str, Variable] = {}
1665+
globals = context.variables._suite.as_dict()
1666+
vars = entry.get_first_or_self().variables()
1667+
vars_dict = vars.as_dict() if vars is not None else {}
1668+
for k, v in context.variables._test.as_dict().items():
1669+
if (k not in globals or globals[k] != v) and (k in vars_dict):
1670+
result[k] = self._create_variable(k, v)
1671+
return result
17201672

1721-
for i, v in enumerate(value[start:], start or 0):
1722-
result[str(i)] = self._create_variable(str(i).zfill(padding), v)
1723-
c += 1
1724-
if count is not None and c >= count:
1725-
break
1673+
def _get_local_variables(self, context: Any, entry: Any) -> MutableMapping[str, Variable]:
1674+
result: MutableMapping[str, Variable] = {}
1675+
vars = entry.get_first_or_self().variables()
1676+
if self._current_exception is not None:
1677+
result["${EXCEPTION}"] = self._create_variable(
1678+
"${EXCEPTION}",
1679+
self._current_exception,
1680+
VariablePresentationHint(kind="virtual"),
1681+
)
1682+
if vars is not None:
1683+
p = entry.parent() if entry.parent else None
1684+
globals = (
1685+
(p.get_first_or_self().variables() if p is not None else None)
1686+
or context.variables._test
1687+
or context.variables._suite
1688+
or context.variables._global
1689+
).as_dict()
1690+
suite_vars = (context.variables._suite or context.variables._global).as_dict()
1691+
for k, v in vars.as_dict().items():
1692+
if (k not in globals or globals[k] != v) and (
1693+
entry.handler is None or k not in suite_vars or suite_vars[k] != v
1694+
):
1695+
result[k] = self._create_variable(k, v)
1696+
if entry.handler is not None and self.get_handler_args(entry.handler):
1697+
for argument in self.get_handler_args(entry.handler).argument_names:
1698+
name = f"${{{argument}}}"
1699+
try:
1700+
value = vars[name]
1701+
except (SystemExit, KeyboardInterrupt):
1702+
raise
1703+
except BaseException as e:
1704+
value = str(e)
1705+
result[name] = self._create_variable(name, value)
1706+
return result
17261707

1727-
elif filter == "named":
1728-
value = self._variables_cache.get(variables_reference, None)
1708+
def _get_cached_variables(self, value: Any) -> MutableMapping[str, Variable]:
1709+
result: MutableMapping[str, Variable] = {}
1710+
if value is not None and isinstance(value, Mapping):
1711+
result["len()"] = self._create_variable("len()", len(value))
1712+
for i, (k, v) in enumerate(value.items()):
1713+
result[repr(i)] = self._create_variable(repr(k), v)
1714+
if i >= MAX_VARIABLE_ITEMS_DISPLAY:
1715+
result["Unable to handle"] = self._create_variable(
1716+
"Unable to handle",
1717+
f"Maximum number of items ({MAX_VARIABLE_ITEMS_DISPLAY}) reached.",
1718+
)
1719+
break
1720+
elif value is not None and isinstance(value, Sequence) and not isinstance(value, str):
1721+
result["len()"] = self._create_variable("len()", len(value))
1722+
return result
17291723

1730-
if value is not None and isinstance(value, Mapping):
1731-
for i, (k, v) in enumerate(value.items(), start or 0):
1732-
result[repr(i)] = self._create_variable(repr(k), v)
1733-
if count is not None and i >= count:
1734-
break
1735-
elif value is not None and isinstance(value, Sequence) and not isinstance(value, str):
1736-
result.update({"len()": self._create_variable("len()", len(value))})
1724+
def _get_variables_indexed(
1725+
self,
1726+
variables_reference: int,
1727+
start: Optional[int],
1728+
count: Optional[int],
1729+
) -> List[Variable]:
1730+
result: MutableMapping[str, Any] = {}
1731+
value = self._variables_cache.get(variables_reference, None)
1732+
if value is not None:
1733+
c = 0
1734+
padding = len(str(len(value)))
1735+
for i, v in enumerate(value[start:], start or 0):
1736+
result[str(i)] = self._create_variable(str(i).zfill(padding), v)
1737+
c += 1
1738+
if count is not None and c >= count:
1739+
break
1740+
return list(result.values())
17371741

1742+
def _get_variables_named(
1743+
self,
1744+
variables_reference: int,
1745+
start: Optional[int],
1746+
count: Optional[int],
1747+
) -> List[Variable]:
1748+
result: MutableMapping[str, Any] = {}
1749+
value = self._variables_cache.get(variables_reference, None)
1750+
if value is not None and isinstance(value, Mapping):
1751+
for i, (k, v) in enumerate(value.items(), start or 0):
1752+
result[repr(i)] = self._create_variable(repr(k), v)
1753+
if count is not None and i >= count:
1754+
break
1755+
elif value is not None and isinstance(value, Sequence) and not isinstance(value, str):
1756+
result["len()"] = self._create_variable("len()", len(value))
17381757
return list(result.values())
17391758

17401759
IS_VARIABLE_RE: ClassVar = re.compile(r"^[$@&]\{.*\}(\[[^\]]*\])?$")

0 commit comments

Comments
 (0)