Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save blakeNaccarato/8352c9b01bd6768a193440c0c0c3e442 to your computer and use it in GitHub Desktop.
Save blakeNaccarato/8352c9b01bd6768a193440c0c0c3e442 to your computer and use it in GitHub Desktop.
VSCode and Python environment variables in UNIX

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.

The workaround

Install PowerShell

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.

Update VSCode workspace settings

Then, e.g. for Linux in your workspace settings.json:

"terminal.integrated.defaultProfile.linux": "pwsh",

Install Set-PsEnv and modify your PowerShell profile

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.

All done!

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.

Notes

Debugging and launch.json

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",
},

Tasks and tasks.json

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.

A note on (.venv) popping up twice

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.

A note on pwsh, environment variables, and the $DISPLAY environment variable in wsl

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment