The Problem
This will probably not be a huge revelation to every one, since this info is available in public documentation. Yet for a long time, my impression of VS Code debugging interface was that it's a pain to configure. If you only need to debug a single script - sure, there's a button for that. If you need to debug a simple Django project - there is a preset for you. But what if you're working on several projects and each one starts and runs tests from a shell script or other task runner and you need to debug a test under specific task parameters? There's no way I'm gonna waste time making sure that VS Code passes the same command-line arguments to the debugger when I want to debug a unit test.
Yes, you can drop into pdb
after running code in your usual way. But pdb
has a terminal interface that requires training and I don't like it.
The Solution
Turns out there's a Microsoft package called debugpy
that allows you to connect to VS Code debugger from anywhere in your code. The setup guide is posted on the VS Code website:

Everything you need should be available there, but I'll still leave here a quick recipe for my future self.
The Recipe
1. Make sure you have `debugpy` installed in your project's virtual environment:
pip install debugpy
2. Open your global VS Code settings:
Ctrl+Shift+P
Preferences: Open Settings (JSON)
3. Add the following launch config:
"launch": {
"version": "0.2.0",
"configurations": [
{
"name": "Python: Attach",
"type": "python",
"request": "attach",
"connect": {
"host": "localhost",
"port": 5678
},
"pathMappings": [
{
"localRoot": "~",
"remoteRoot": "~"
}
]
}
]
}
(You can put it into the workspace-scoped launch config instead of course. For that, search for the command "Open launch.json".)
4. Put this snippet in your code:
import debugpy
debugpy.listen(5678)
print("Waiting for debugger")
debugpy.wait_for_client()
5. Put a breakpoint where you need it through VS Code.
6. Run your code and after you see the message run the "Python: Attach" configuration in the debugger tab. There you go.
7. If you're using pytest
make sure to pass the -s
flag to it, otherwise, it will capture the printed message and you won't see it.