Skip to content

Instantly share code, notes, and snippets.

@csghone
Last active November 21, 2022 15:21
Show Gist options
  • Save csghone/e095e69415ebfb420bff52f631718d4b to your computer and use it in GitHub Desktop.
Save csghone/e095e69415ebfb420bff52f631718d4b to your computer and use it in GitHub Desktop.
Python "breakpoint()" with VSCode
import os
import sys
import debugpy
# Based on
# https://stackoverflow.com/questions/69690653/remote-debugging-with-debugpy-works-from-code-but-not-from-command-line
# To use with 'breakpoint()'
# export PYTHONBREAKPOINT=vscode_debugger.wait_for_vscode
"""
VS Code configuration
Add the following to the "configurations" in your launch.json.
You can get the port number by running (To avoid clashes with multiple users):
python -c 'import os; print((20000 + os.getuid()) % 65536)'
{
"name": "Python: Attach to process",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 21001 // Refer comment above or 5678 for Windows
}
}
Using this in code:
To use with `breakpoint()` set `PYTHONBREAKPOINT=vscode_debugger.wait_for_vscode` before execution.
Alternatively,
`from vscode_debugger import *`
Add 'wait_for_vscode()' just before the line you want a breakpoint.
Alternately, add @vscode_debug decorator to any function you want a breakpoint.
Once the debugger connects, execution slows down.
You can speed it up a bit by adding 'disable_debugpy()' at the point
where you don't need a debugger. Breakpoints/stepping won't work after the
'disable_debugpy()' line
"""
LISTEN_ACTIVE = False
DEBUG_PORT = 5678
if hasattr(os, getuid):
DEBUG_PORT = (30000 + os.getuid()) % 65536 # Edit if on Windows
def disable_debugpy():
debugpy.server.api.get_global_debugger().disable_tracing()
print("Disabling debugpy trace", file=sys.stderr)
def wait_for_vscode(cond=True, breakpoint=True):
global LISTEN_ACTIVE
if not LISTEN_ACTIVE:
debugpy.listen(("localhost", DEBUG_PORT))
LISTEN_ACTIVE = True
if cond and not debugpy.is_client_connected():
print("Wait for DebugPy connection...", file=sys.stderr)
debugpy.wait_for_client()
if cond:
debugpy.breakpoint()
def vscode_debug_exception(func, *args, **kwargs):
def inner():
try:
return func(*args, **kwargs)
except Exception as e:
import traceback; traceback.print_exc()
print(f"Exception: {type(e)}: {e} occured",
f"Will exit function: '{func.__name__}' and resume from there",
file=sys.stderr)
wait_for_vscode()
return inner
def vscode_debug(func, *args, **kwargs):
def inner():
wait_for_vscode()
ret_val = func(*args, **kwargs)
disable_debugpy()
return ret_val
return inner
@vscode_debug_exception
def example_exception():
print("Raising NameError Exception")
raise NameError
print("This will not execute!!")
@vscode_debug
def example_function():
print("Debugpy waits at start of function")
def example_breakpoint1():
try:
raise NameError
except:
print("Wait for DebugPy connection")
wait_for_vscode()
print("Debugger will not execute this line before connection")
def example_breakpoint2():
try:
raise NameError
except:
print("Wait for DebugPy connection")
breakpoint() # Will work if export PYTHONBREAKPOINT=vscode_debugger.wait_for_vscode
print("This will execute after debugger is connected")
def check_execution_speed():
import time
start_time = time.time()
_ = [x for x in range(1, 100000000)]
runtime = time.time() - start_time
print(f"Runtime: {runtime} seconds", flush=True)
def main():
for i in range(1, 10):
wait_for_vscode(cond=(i==5))
print(i)
example_exception()
example_function()
example_breakpoint1()
example_breakpoint2()
# When debugger is connected, execution speed drops.
# disable_debugpy() improves the speed, but not fully back to original levels.
check_execution_speed()
disable_debugpy() # Stepping/Breakpoints cannot work after this point.
check_execution_speed()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment