Originally posted in microsoft/vscode-python#944 (comment)
A (perhaps not so awesome) workaround is to not use bash and instead use PowerShell as the default terminal for VSCode, then set up your PowerShell profile to load the environment and activate the virtual environment. Now, "Run Python File" and debugging will all load the proper environment. If you have certain tasks in tasks.json
specially written for bash
, most of these will still work, as pwsh
has access to all the system utilities including sudo
. See my note at the end of this comment for more details on tasks.json
.
Install PowerShell in your distro by adding the Linux Software Repository for Microsoft Products and running sudo apt install powershell
afterwards, or else follow one of these guides.
Then, e.g. for Linux in your workspace settings.json
:
"terminal.integrated.defaultProfile.linux": "pwsh",
Then close your VSCode integrated terminal and re-open it, and it should open pwsh
instead of bash
. Install Set-PsEnv like Install-Module -Name Set-PsEnv
. Do this in pwsh
not bash
.
Then run code $PROFILE
which should open /home/user/.config/powershell/Microsoft.PowerShell_profile.ps1
(e.g. for a user named user
), and copy/paste the following into it:
function Set-Env {
# If there is an `.env` file in the PWD, load environment variables from it
Set-PsEnv
# If there is a Python virtual environment in the PWD, activate it
$COMMON = 'bin\Activate.ps1'
# ".venv"
$PATH_VENV = '.venv'
if (Test-Path $PATH_VENV) { & $PATH_VENV\$COMMON }
# "venv" (no dot)
$PATH_VENV = 'venv'
if (Test-Path $PATH_VENV) { & $PATH_VENV\$COMMON }
}
Set-Env
Note: I call a function inside the profile to shield those variables from being loaded into the interactive terminal session. Note that $script:VAR
or similar do not protect the scope of these variables since the profile context is the terminal context.
Now close and re-open the integrated terminal and your virtual environment should load, and your environment variables should load, and running Python files, debugging, etc. should work. Modify the profile above as necessary for your specific use-case.
You must debug with "console": "integratedTerminal",
as opposed to internalConsole
, or else your environment will not load properly.
{
"name": "Python",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
},
In order for tasks to load the proper environment variables in tasks.json
, they must be formed like so:
{
"label": "Example task",
"type": "process",
"command": "pwsh",
"args": ["-Command", "python -m my_example_module"],
"problemMatcher": []
},
This ensures that your PowerShell profile has a chance to load environment variables and such before running your Python code.
We are activating the environment in our PowerShell profile and via a setting in VSCode. You can disable one or the other by deleting the associated lines in the PowerShell profile above or setting the following in your workspace settings.json
:
"python.terminal.activateEnvironment": false,
I prefer to do my environment activation in the PowerShell profile, but it is just a matter of preference.
Somehow, pwsh
seems to automatically intuit the appropriate $DISPLAY
environment variable in wsl
. Some funny-business is usually needed in bash
on wsl
, but pwsh
seems to do it for us.
Okay I must have been leaking my environment from bash or something, because what I crossed out above isn't true. You really do have to explicitly set your display in the PowerShell profile, like so:
$Env:DISPLAY="$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0"
$Env:LIBGL_ALWAYS_INDIRECT=1
Note that we refer to environment variables as $Env:DISPLAY
, not just $DISPLAY
, that is important!