robotcode-debugger 2.3.1__tar.gz → 2.5.0__tar.gz

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.
Files changed (24) hide show
  1. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/.gitignore +5 -1
  2. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/PKG-INFO +1 -1
  3. robotcode_debugger-2.5.0/src/robotcode/debugger/__version__.py +1 -0
  4. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/debugger.py +29 -39
  5. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/launcher/client.py +55 -6
  6. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/launcher/server.py +13 -2
  7. robotcode_debugger-2.3.1/src/robotcode/debugger/__version__.py +0 -1
  8. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/README.md +0 -0
  9. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/pyproject.toml +0 -0
  10. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/__init__.py +0 -0
  11. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/cli.py +0 -0
  12. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/dap_types.py +0 -0
  13. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/default_capabilities.py +0 -0
  14. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/hooks.py +0 -0
  15. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/id_manager.py +0 -0
  16. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/launcher/__init__.py +0 -0
  17. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/launcher/cli.py +0 -0
  18. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/launcher/run.py +0 -0
  19. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/listeners.py +0 -0
  20. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/mixins.py +0 -0
  21. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/protocol.py +0 -0
  22. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/py.typed +0 -0
  23. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/run.py +0 -0
  24. {robotcode_debugger-2.3.1 → robotcode_debugger-2.5.0}/src/robotcode/debugger/server.py +0 -0
@@ -334,4 +334,8 @@ bundled/libs
334
334
  results/
335
335
 
336
336
  # kilocode
337
- .kilocode/
337
+ .kilocode/
338
+
339
+ # .agents
340
+ .agents/
341
+ skills-lock.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: robotcode-debugger
3
- Version: 2.3.1
3
+ Version: 2.5.0
4
4
  Summary: RobotCode Debugger for Robot Framework
5
5
  Project-URL: Homepage, https://robotcode.io
6
6
  Project-URL: Donate, https://opencollective.com/robotcode
@@ -0,0 +1 @@
1
+ __version__ = "2.5.0"
@@ -36,11 +36,13 @@ from robot.api.parsing import get_model
36
36
  from robot.errors import VariableError
37
37
  from robot.output import LOGGER
38
38
  from robot.running import EXECUTION_CONTEXTS, Keyword, TestCase, TestSuite
39
+ from robot.running.model import Try
40
+ from robot.utils import Matcher as RobotMatcher
39
41
  from robot.variables import evaluate_expression
40
42
 
41
43
  from robotcode.core.event import event
42
44
  from robotcode.core.utils.logging import LoggingDescriptor
43
- from robotcode.robot.utils import get_robot_version
45
+ from robotcode.robot.utils import RF_VERSION
44
46
 
45
47
  from .dap_types import (
46
48
  Breakpoint,
@@ -72,16 +74,12 @@ from .dap_types import (
72
74
  )
73
75
  from .id_manager import IdManager
74
76
 
75
- if get_robot_version() >= (5, 0):
76
- from robot.running.model import Try
77
- from robot.utils import Matcher as RobotMatcher
78
-
79
- if get_robot_version() >= (7, 0):
77
+ if RF_VERSION >= (7, 0):
80
78
  from robot.running import UserKeyword as UserKeywordHandler
81
79
  else:
82
80
  from robot.running.userkeyword import UserKeywordHandler
83
81
 
84
- if get_robot_version() >= (6, 1):
82
+ if RF_VERSION >= (6, 1):
85
83
 
86
84
  def internal_evaluate_expression(expression: str, variable_store: Any) -> Any:
87
85
  return evaluate_expression(expression, variable_store)
@@ -303,7 +301,7 @@ class DebugLoggerBase:
303
301
  self.steps: List[Any] = []
304
302
 
305
303
 
306
- if get_robot_version() < (7, 0):
304
+ if RF_VERSION < (7, 0):
307
305
 
308
306
  class DebugLogger(DebugLoggerBase):
309
307
  def start_keyword(self, kw: Any) -> None:
@@ -1119,7 +1117,7 @@ class Debugger:
1119
1117
 
1120
1118
  self.remove_stackframe_entry(longname, type, source, line_no)
1121
1119
 
1122
- if get_robot_version() >= (7, 0):
1120
+ if RF_VERSION >= (7, 0):
1123
1121
 
1124
1122
  def get_current_keyword_handler(self, name: str) -> UserKeywordHandler:
1125
1123
  return EXECUTION_CONTEXTS.current.namespace.get_runner(name).keyword
@@ -1252,7 +1250,7 @@ class Debugger:
1252
1250
 
1253
1251
  return False
1254
1252
 
1255
- if get_robot_version() >= (7, 0):
1253
+ if RF_VERSION >= (7, 0):
1256
1254
 
1257
1255
  def _get_step_data(self, step: Any) -> Any:
1258
1256
  return step
@@ -1262,31 +1260,23 @@ class Debugger:
1262
1260
  def _get_step_data(self, step: Any) -> Any:
1263
1261
  return step.data
1264
1262
 
1265
- if get_robot_version() < (5, 0):
1266
-
1267
- def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1268
- if not message:
1269
- return True
1270
- return False
1271
- else:
1263
+ def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1264
+ if not message:
1265
+ return True
1272
1266
 
1273
- def is_not_caugthed_by_except(self, message: Optional[str]) -> bool:
1274
- if not message:
1275
- return True
1267
+ # TODO resolve variables in exception message
1276
1268
 
1277
- # TODO resolve variables in exception message
1278
-
1279
- if self.debug_logger:
1280
- if self.debug_logger.steps:
1281
- for branch in [
1282
- self._get_step_data(f)
1283
- for f in reversed(self.debug_logger.steps)
1284
- if isinstance(self._get_step_data(f), Try)
1285
- ]:
1286
- for except_branch in branch.except_branches:
1287
- if self._should_run_except(except_branch, message):
1288
- return False
1289
- return True
1269
+ if self.debug_logger:
1270
+ if self.debug_logger.steps:
1271
+ for branch in [
1272
+ self._get_step_data(f)
1273
+ for f in reversed(self.debug_logger.steps)
1274
+ if isinstance(self._get_step_data(f), Try)
1275
+ ]:
1276
+ for except_branch in branch.except_branches:
1277
+ if self._should_run_except(except_branch, message):
1278
+ return False
1279
+ return True
1290
1280
 
1291
1281
  def end_keyword(self, name: str, attributes: AttributeDict) -> None:
1292
1282
  if self.state == State.CallKeyword:
@@ -1602,7 +1592,7 @@ class Debugger:
1602
1592
 
1603
1593
  return Variable(name=name, value=self.debug_repr.repr(value), type=repr(type(value)))
1604
1594
 
1605
- if get_robot_version() >= (7, 0):
1595
+ if RF_VERSION >= (7, 0):
1606
1596
 
1607
1597
  def get_handler_args(self, handler: UserKeywordHandler) -> Any:
1608
1598
  return handler.args
@@ -1764,7 +1754,7 @@ class Debugger:
1764
1754
  SPLIT_LINE: ClassVar = re.compile(r"(?= {2,}| ?\t)\s*")
1765
1755
  CURRDIR: ClassVar = re.compile(r"(?i)\$\{CURDIR\}")
1766
1756
 
1767
- if get_robot_version() >= (7, 0):
1757
+ if RF_VERSION >= (7, 0):
1768
1758
 
1769
1759
  def _run_keyword(self, kw: Keyword, context: Any) -> Any:
1770
1760
  return kw.run(context.steps[-1][1], context)
@@ -1774,7 +1764,7 @@ class Debugger:
1774
1764
  def _run_keyword(self, kw: Keyword, context: Any) -> Any:
1775
1765
  return kw.run(context)
1776
1766
 
1777
- if get_robot_version() >= (7, 2):
1767
+ if RF_VERSION >= (7, 2):
1778
1768
 
1779
1769
  @staticmethod
1780
1770
  def check_message_is_logged(listener: Any, msg: Any) -> bool:
@@ -1963,7 +1953,7 @@ class Debugger:
1963
1953
  result = None
1964
1954
 
1965
1955
  if len(test.body):
1966
- if get_robot_version() >= (7, 3):
1956
+ if RF_VERSION >= (7, 3):
1967
1957
  result = self._execute_keywords_with_delayed_logging_v73(test.body, evaluate_context)
1968
1958
  else:
1969
1959
  result = self._execute_keywords_with_delayed_logging_legacy(test.body, evaluate_context)
@@ -2003,7 +1993,7 @@ class Debugger:
2003
1993
  result = e
2004
1994
  break
2005
1995
  finally:
2006
- if get_robot_version() <= (7, 2):
1996
+ if RF_VERSION <= (7, 2):
2007
1997
  self._process_delayed_log_messages()
2008
1998
  return result
2009
1999
 
@@ -2161,7 +2151,7 @@ class Debugger:
2161
2151
 
2162
2152
  return result or None
2163
2153
 
2164
- if get_robot_version() >= (7, 0):
2154
+ if RF_VERSION >= (7, 0):
2165
2155
 
2166
2156
  def _get_keywords_from_lib(self, lib: Any) -> Any:
2167
2157
  return lib.keywords
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import logging
5
+ import weakref
4
6
  from typing import Any, Optional, Sequence
5
7
 
6
8
  from robotcode.core.event import event
@@ -38,6 +40,17 @@ class DAPClientError(Exception):
38
40
  pass
39
41
 
40
42
 
43
+ class _DAPClientState:
44
+ __slots__ = ("closed", "logger", "loop", "protocol", "transport")
45
+
46
+ def __init__(self, logger: logging.Logger) -> None:
47
+ self.logger = logger
48
+ self.loop: Optional[asyncio.AbstractEventLoop] = None
49
+ self.protocol: Optional[DAPClientProtocol] = None
50
+ self.transport: Optional[asyncio.BaseTransport] = None
51
+ self.closed = False
52
+
53
+
41
54
  class DAPClient:
42
55
  _logger = LoggingDescriptor()
43
56
 
@@ -48,8 +61,43 @@ class DAPClient:
48
61
  ) -> None:
49
62
  self.parent = parent
50
63
  self.tcp_params = tcp_params
51
- self._protocol: Optional[DAPClientProtocol] = None
52
- self._transport: Optional[asyncio.BaseTransport] = None
64
+ self._state = _DAPClientState(
65
+ logging.getLogger(f"{type(self).__module__}.{type(self).__qualname__}"),
66
+ )
67
+ self._finalizer = weakref.finalize(self, DAPClient._finalize_resources, self._state)
68
+
69
+ @staticmethod
70
+ def _finalize_resources(state: _DAPClientState) -> None:
71
+ if state.closed or state.transport is None:
72
+ return
73
+
74
+ try:
75
+ if state.loop is not None and not state.loop.is_closed() and state.loop.is_running():
76
+ state.loop.call_soon_threadsafe(state.transport.close)
77
+ else:
78
+ state.transport.close()
79
+ except BaseException:
80
+ pass
81
+
82
+ state.logger.debug(
83
+ "DAPClient was garbage collected without calling close(); the transport was closed best-effort only.",
84
+ )
85
+
86
+ @property
87
+ def _protocol(self) -> Optional[DAPClientProtocol]:
88
+ return self._state.protocol
89
+
90
+ @_protocol.setter
91
+ def _protocol(self, value: Optional[DAPClientProtocol]) -> None:
92
+ self._state.protocol = value
93
+
94
+ @property
95
+ def _transport(self) -> Optional[asyncio.BaseTransport]:
96
+ return self._state.transport
97
+
98
+ @_transport.setter
99
+ def _transport(self, value: Optional[asyncio.BaseTransport]) -> None:
100
+ self._state.transport = value
53
101
 
54
102
  @event
55
103
  def on_closed(sender) -> None: ...
@@ -61,11 +109,10 @@ class DAPClient:
61
109
  self._transport = None
62
110
  self._protocol = None
63
111
 
112
+ self._state.closed = True
113
+ self._finalizer.detach()
64
114
  self.on_closed(self)
65
115
 
66
- def __del__(self) -> None:
67
- self.close()
68
-
69
116
  @_logger.call
70
117
  def on_connection_lost(self, sender: Any, exc: Optional[BaseException]) -> None:
71
118
  if sender == self._protocol:
@@ -76,6 +123,8 @@ class DAPClient:
76
123
  async def wait() -> None:
77
124
  while self._protocol is None:
78
125
  try:
126
+ current_loop = asyncio.get_running_loop()
127
+ self._state.loop = current_loop
79
128
  if self.tcp_params.host is not None:
80
129
  if isinstance(self.tcp_params.host, Sequence):
81
130
  host = self.tcp_params.host[0]
@@ -86,7 +135,7 @@ class DAPClient:
86
135
  (
87
136
  self._transport,
88
137
  protocol,
89
- ) = await asyncio.get_running_loop().create_connection(
138
+ ) = await current_loop.create_connection(
90
139
  self._create_protocol,
91
140
  host=host,
92
141
  port=self.tcp_params.port,
@@ -11,7 +11,7 @@ from robotcode.core.types import ServerMode, TcpParams
11
11
  from robotcode.core.utils.logging import LoggingDescriptor
12
12
  from robotcode.jsonrpc2.protocol import rpc_method
13
13
  from robotcode.jsonrpc2.server import JsonRPCServer
14
- from robotcode.robot.utils import get_robot_version
14
+ from robotcode.robot.utils import RF_VERSION
15
15
 
16
16
  from ..cli import DEBUGGER_DEFAULT_PORT, DEBUGPY_DEFAULT_PORT
17
17
  from ..dap_types import (
@@ -85,6 +85,11 @@ class LauncherDebugAdapterProtocol(DebugAdapterProtocol):
85
85
  def connected(self) -> bool:
86
86
  return self._client is not None and self._client.connected
87
87
 
88
+ def close(self) -> None:
89
+ if self._client is not None:
90
+ self._client.close()
91
+ self._client = None
92
+
88
93
  @rpc_method(name="initialize", param_type=InitializeRequestArguments)
89
94
  async def _initialize(self, arguments: InitializeRequestArguments, *args: Any, **kwargs: Any) -> Capabilities:
90
95
  self._initialize_arguments = arguments
@@ -189,7 +194,7 @@ class LauncherDebugAdapterProtocol(DebugAdapterProtocol):
189
194
 
190
195
  run_args = []
191
196
 
192
- if get_robot_version() >= (6, 0) and languages:
197
+ if RF_VERSION >= (6, 0) and languages:
193
198
  for lang in languages:
194
199
  run_args += ["--language", lang]
195
200
 
@@ -352,3 +357,9 @@ class LauncherServer(JsonRPCServer[LauncherDebugAdapterProtocol]):
352
357
  self.protocol = LauncherDebugAdapterProtocol(debugger_script=self.debugger_script)
353
358
 
354
359
  return self.protocol
360
+
361
+ def _close(self) -> None:
362
+ if self.protocol is not None:
363
+ self.protocol.close()
364
+
365
+ super()._close()
@@ -1 +0,0 @@
1
- __version__ = "2.3.1"