From 117704df3dc07cc15c05644eeb333077e4f65215 Mon Sep 17 00:00:00 2001 From: Pavel Minaev Date: Tue, 26 Mar 2024 15:27:50 -0700 Subject: [PATCH] Remove comment that is no longer applicable. Use consistent naming. --- src/debugpy/server/eval.py | 2 +- src/debugpy/server/tracing/__init__.py | 52 +++++++++++++------------- src/debugpy/server/tracing/tracer.py | 23 ++++-------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/src/debugpy/server/eval.py b/src/debugpy/server/eval.py index 6f940b5e..839d3368 100644 --- a/src/debugpy/server/eval.py +++ b/src/debugpy/server/eval.py @@ -144,7 +144,7 @@ class Scope(Variable): pass else: PyFrame_LocalsToFast( - ctypes.py_object(frame.frame_object), ctypes.c_int(0) + ctypes.py_object(frame.python_frame), ctypes.c_int(0) ) super().__init__(frame, name, ScopeObject()) diff --git a/src/debugpy/server/tracing/__init__.py b/src/debugpy/server/tracing/__init__.py index 32d008c9..5ade5f96 100644 --- a/src/debugpy/server/tracing/__init__.py +++ b/src/debugpy/server/tracing/__init__.py @@ -261,7 +261,7 @@ class Thread: except ValueError: raise ValueError(f"Can't get frames for inactive Thread({self.id})") for python_frame, _ in traceback.walk_stack(python_frame): - frame = StackFrame.from_frame_object(self, python_frame) + frame = StackFrame.from_python_frame(self, python_frame) log.info("{0}", f"{self}: {frame}") if not is_internal_python_frame(python_frame): yield frame @@ -271,26 +271,27 @@ class Thread: class StackFrame: """ Represents a DAP StackFrame object. Instances must never be created directly; - use StackFrame.from_frame_object() instead. + use StackFrame.from_python_frame() instead. """ - thread: Thread - frame_object: FrameType - id: int + + thread: Thread + python_frame: FrameType + _source: Source | None _scopes: List[Scope] _all: ClassVar[Dict[int, "StackFrame"]] = {} - def __init__(self, thread: Thread, frame_object: FrameType): + def __init__(self, thread: Thread, python_frame: FrameType): """ Create a new StackFrame object for the given thread and frame object. Do not - invoke directly; use StackFrame.from_frame_object() instead. + invoke directly; use StackFrame.from_python_frame() instead. """ self.id = new_dap_id() self.thread = thread - self.frame_object = frame_object + self.python_frame = python_frame self._source = None self._scopes = None self._all[self.id] = self @@ -298,39 +299,39 @@ class StackFrame: def __getstate__(self) -> dict: return { "id": self.id, - "name": self.frame_object.f_code.co_name, + "name": self.python_frame.f_code.co_name, "source": self.source(), - "line": self.frame_object.f_lineno, + "line": self.python_frame.f_lineno, "column": 1, # TODO # TODO: "endLine", "endColumn", "moduleId", "instructionPointerReference" } def __repr__(self) -> str: - result = f"StackFrame({self.id}, {self.frame_object}" - if is_internal_python_frame(self.frame_object): + result = f"StackFrame({self.id}, {self.python_frame}" + if is_internal_python_frame(self.python_frame): result += ", internal=True" result += ")" return result - + @property def line(self) -> int: - return self.frame_object.f_lineno + return self.python_frame.f_lineno def source(self) -> Source: if self._source is None: # No need to sync this since all instances created from the same path # are equivalent for all purposes. - self._source = Source(self.frame_object.f_code.co_filename) + self._source = Source(self.python_frame.f_code.co_filename) return self._source @classmethod - def from_frame_object( - self, thread: Thread, frame_object: FrameType + def from_python_frame( + self, thread: Thread, python_frame: FrameType ) -> "StackFrame": for frame in self._all.values(): - if frame.thread is thread and frame.frame_object is frame_object: + if frame.thread is thread and frame.python_frame is python_frame: return frame - return StackFrame(thread, frame_object) + return StackFrame(thread, python_frame) @classmethod def get(self, id: int) -> "StackFrame": @@ -339,14 +340,14 @@ class StackFrame: def scopes(self) -> List[Scope]: if self._scopes is None: self._scopes = [ - Scope(self, "local", self.frame_object.f_locals), - Scope(self, "global", self.frame_object.f_globals), + Scope(self, "local", self.python_frame.f_locals), + Scope(self, "global", self.python_frame.f_globals), ] return self._scopes def evaluate(self, source: str, mode: Literal["eval", "exec", "single"] = "eval") -> object: code = compile(source, "", mode) - return eval(code, self.frame_object.f_globals, self.frame_object.f_locals) + return eval(code, self.python_frame.f_globals, self.python_frame.f_locals) @classmethod def invalidate(self, thread: Thread): @@ -354,6 +355,7 @@ class StackFrame: VariableContainer.invalidate(*frames) for frame in frames: del self._all[frame.id] + frame.python_frame = None @dataclass @@ -418,8 +420,8 @@ class Condition: try: result = eval( self._code, - frame.frame_object.f_globals, - frame.frame_object.f_locals, + frame.python_frame.f_globals, + frame.python_frame.f_locals, ) return bool(result) except BaseException as exc: @@ -510,7 +512,7 @@ class LogMessage: """ try: return eval( - self._code, frame.frame_object.f_globals, frame.frame_object.f_locals + self._code, frame.python_frame.f_globals, frame.python_frame.f_locals ) except BaseException as exc: log.exception( diff --git a/src/debugpy/server/tracing/tracer.py b/src/debugpy/server/tracing/tracer.py index 2f05716b..acbbfb24 100644 --- a/src/debugpy/server/tracing/tracer.py +++ b/src/debugpy/server/tracing/tracer.py @@ -2,15 +2,7 @@ # Licensed under the MIT License. See LICENSE in the project root # for license information. -# Once callbacks are registered they are invoked even during finalization when the -# Python is shutting down. Thus, trace_* methods, and any other methods that they -# invoke, must not use any globals from this or other modules (including globals -# that represent imported modules or defined classes!) until it checks that they -# are present, or preload them into local variables or object attributes in advance. -# To facilitate this, Tracer is defined in a separate submodule which should not -# contain ANY top-level imports other than typing nor definitions other than the -# class itself. All other imports must be done in function or class scope. - +import gc import inspect import sys import threading @@ -282,7 +274,7 @@ class Tracer: else Thread.from_python_thread(threading.current_thread()) ) - def _suspend_this_thread(self, frame_obj: FrameType): + def _suspend_this_thread(self, python_frame: FrameType): """ Suspends execution of this thread until the current stop ends. """ @@ -293,19 +285,20 @@ class Tracer: return log.info(f"{thread} suspended.") - thread.current_frame = frame_obj + thread.current_frame = python_frame while self._stopped_by is not None: _cvar.wait() thread.current_frame = None - StackFrame.invalidate(thread) log.info(f"{thread} resumed.") + StackFrame.invalidate(thread) + gc.collect() step = self._steps.get(thread, None) if step is not None and step.origin is None: # This step has just begun - update the Step object with information # about current frame that will be used to track step completion. - step.origin = frame_obj - step.origin_line = frame_obj.f_lineno + step.origin = python_frame + step.origin_line = python_frame.f_lineno def _trace_line(self, code: CodeType, line_number: int): thread = self._this_thread() @@ -380,7 +373,7 @@ class Tracer: f"Stack frame {frame} stopping at breakpoints {[bp.__getstate__() for bp in stop_bps]}." ) self._begin_stop(thread, "breakpoint", stop_bps) - self._suspend_this_thread(frame.frame_object) + self._suspend_this_thread(frame.python_frame) finally: del frame del python_frame