From b1dff33b579fb3e01efddafe75510ce8c3e5303c Mon Sep 17 00:00:00 2001
From: Google Colaboratory Team
Date: Fri, 11 Jul 2025 12:29:28 -0700
Subject: [PATCH] No public description
PiperOrigin-RevId: 782071435
---
google/colab/_debugpy.py | 83 +---------------------------------------
1 file changed, 2 insertions(+), 81 deletions(-)
diff --git a/google/colab/_debugpy.py b/google/colab/_debugpy.py
index babd86ef..cef25951 100644
--- a/google/colab/_debugpy.py
+++ b/google/colab/_debugpy.py
@@ -1,101 +1,22 @@
"""Tools to enable debugpy attachment to a process."""
import sys
-import threading
-import time
-
-import debugpy
from google.colab import _debugpy_repr
from google.colab import _variable_inspector
-import IPython
-import portpicker
_dap_port = None
def enable_attach_async(enable_inspector=False):
- """Enable a debugger to attach to this process.
+ """Overrides python's breakpoint hook.
Args:
enable_inspector: Enable variable inspector.
Returns:
- The debug adapter port which can be connected to using the Debug Adapter
- Proxy protocol.
+ None
"""
- global _dap_port
- if _dap_port:
- return _dap_port
-
- # Changes here should be reflected in our internal debugpy config.
- debugpy.configure({
- # We don't use qt, so we disable support to avoid spurious imports.
- 'qt': 'none',
- # b/180567283: Disable monkey patching subprocess calls which isn't
- # needed for Colab and can cause issues.
- 'subProcess': False,
- })
# debugpy overrides python's `breakpoint()` hook; we restore the original
# hook, as it works fine with our stdin handling, and debugpy's hook hangs.
sys.breakpointhook = sys.__breakpointhook__
-
- _dap_port = portpicker.pick_unused_port()
-
- main_thread = threading.current_thread()
- # Prevent debugpy from tracing the current thread.
- main_thread.pydev_do_not_trace = True
-
- def attachment_entry():
- # The client will retry the connection a few times to avoid the inherent
- # raciness of this.
- debugpy.listen(_dap_port)
-
- if enable_inspector:
- _debugpy_repr.patch_debugpy_repr()
-
- inspector_thread_started = threading.Event()
-
- def inspector_thread():
- inspector_thread_started.set()
- shell = IPython.get_ipython()
- if not shell:
- return
- _variable_inspector.run(shell, time)
-
- # Need to start this thread after the debugpy.listen() call but before
- # the undo_patch_thread_modules().
- threading.Thread(
- target=inspector_thread, name='_colab_inspector_thread', daemon=True
- ).start()
- inspector_thread_started.wait()
-
- # Debugger tracing isn't needed for just tracebacks, but if full debugging
- # is needed then it needs to be re-enabled while debugging.
- # We want to use `pydevd.stoptrace` but if this is called before we have
- # connected to the debug adapter from the client then it'll send a
- # terminate to the adapter and the adapter will auto-exit before we can
- # connect to it. After the connection then it's OK to terminate since the
- # adapter will not close while there are active connections.
- threading.settrace(None) # for all future threads
- try:
- # Stop debugpy from tracing newly created threads.
- from _pydev_bundle import pydev_monkey # pylint: disable=g-import-not-at-top
-
- pydev_monkey.undo_patch_thread_modules()
- except ModuleNotFoundError:
- # _pydev_bundle may be vendored into either location.
- from pydevd._pydev_bundle import pydev_monkey # pylint: disable=g-import-not-at-top
-
- pydev_monkey.undo_patch_thread_modules()
-
- # Clear the trace flag to allow fetching stack traces.
- main_thread.pydev_do_not_trace = False
-
- # debugpy.listen will spin up another process then start listening for
- # connections from that process. This can take a second or so, but most of it
- # is not by this process. Doing this on a separate thread reduces the impact
- # on kernel initialization.
- threading.Thread(target=attachment_entry).start()
-
- return _dap_port