VSCode: debugging code located in Python virtual environment

Photo by Lux Interaction @ unsplash.com

Problem

In trying to set up a virtual environment(virtualenv) for Python to be used in VSCode, I encountered a situation where I was unable to debug and hit the breakpoints in my code. My first steps were to verify that I was following the documentation for selecting the correct Python interpreter. When this did not solve my problem, I dug deeper into VSCode debugging and virtual environments. Below is what I learned.

Setup

It had been awhile since using VSCode, so I wanted to use a current Python project to refamiliarize myself with the IDE. I also have had limited exposure to virtual environments in Python, and I wanted to make sure that I at least attempted to set up my project properly.

Once my virtual environment was set up, I wanted to double check that I could debug my code in VSCode using the interpreter located in the virtual environment.

Simple Python script

a = 1
b = 2   # put breakpoint here

print(a+b)

Verify correct interpreter is selected

Breakpoints skipped
I continued, and set a breakpoint as indicated in the code above and started debugging in Python. I was expecting my breakpoint to be recognized and for execution to break for inspection, but the script continue to run to completion without ever breaking. I double checked my interpreter selection and tried again. Same behavior.

On a whim I decided to select a different interpreter (the base Anaconda interpreter). The breakpoint was recognized and execution paused for inspection! What? Now I was intrigued.

I tried selecting different interpreters on my machine located in various other older virtual environment setups. Each time the breakpoint was recognized and execution paused. I then realized that my python script file was located inside of my virtual environment directory. It was becoming clear that this could be some kind of path or file location issue.

To test my location hypothosis, I moved my Python script outside of my virtual environment directory, selected the desired inpterpreter and tried debugging again. Success! My breakpoint was recognized and the debugger in VSCode paused for inspection.

Research

While I had solved my immediate problem with debuggging, I was not satisfied. I had stumbled upon a viable solution, but wanted to understand the root cause. It took a bit of searching and reading through GitHub VSCode issues and discussions before finding two separate threads that alluded to a proper explaination and solution.

I also spent some time reading up on how to use Python virtual environments and advice against putting you application code inside of the virtual environment directory. By not doing this it allows for clean separatation and the proper use of the requirements.txt file for properly creating Python environments.

I probably spent 2 hours researching the background to my problem, and while frustrating at times, it was time well spent. Hopefully this post will surface for others searching for a solution to the same problem.

Solution

Best Solution
The better solution is to make sure your project code is NOT located inside of the virtual environment directory structure. This is desired anyway in order to separate your code from the environment setup.


Source: https://github.com/Microsoft/vscode-python/issues/2993

Alternative Solution
There is, however, an alternative solution. I would encourage you to test this out even just to learn how the debug configuration setting works in VSCode.

In this solution, we need to add the configuration "debugStdLib": true to our launch.json file. This will enable the debugging of standard library files located within the virtual environment directory. See Debugging Configuration documentation.


Source: https://github.com/Microsoft/vscode-python/issues/2520

launch.json

{
    "name": "Python: Current File (Integrated Terminal)",
    "type": "python",
    "request": "launch",
    "program": "${file}",
    "console": "integratedTerminal",
    "debugStdLib": true,
},

Having already stumbled across the better solution, I also tested the alternative and added the debugStdLib setting to my launch.json file. Using this approach I was able to set breakpoints for a script located inside of the Python virtual environment directory and pause execution for inspection. I would recommend this approach any time you want to step through standard libraries to learn how they work.

Wrap up

Configuration is everything!

Investigating the solution to my VSCode debug problem for Python virtual environments was definitely tedious, but in the end my original problem makes sense. Having learned more about Python virtual environments, I discovered how to better structure my code and separate it from the environment. In addition, I also learned how to debug code third-party code located inside the virtual environment. This knowledge will definitely be used for future problems I encounter.


Featured image by Lux Interaction @ unsplash.com