How to correctly set PYTHONPATH for Visual Studio Code

111,772

Solution 1

OP seemed to have asked about path syntax for the .env file and the vscode set up so that it finds and reads some custom module files. My problem was similar in that I wanted code to find my custom modules for import in a script. I did not want to put my custom modules in a folder inside my python environment. I also wanted to avoid setting one or more paths as PYTHONPATH for the User Variables in the Windows Environment Variables - but this will work if you want to do it. I am working in vscode in Windows 10.

1) SYNTAX:

a) I found that the following path syntax works in the env file:

PYTHONPATH = C:/0APPS/PYTHON/_MODULES

My .py module files are in this folder.

b) # works for comments in the .env file.

2) VSCODE SET-UP: I found that the following works:

a) Like sunew said at #2 My setup: Use the Explorer in vscode to open at your selected project workspace folder. For me that is Q:\420 PYTHON

b) Give the env file a name, like vscode.env file and place it in that folder at the top level of the workspace.

c) Open vscode settings and search .env where under the Extensions > Python you will find "Python: env file". Edit the box to add your env file name just before .env. e.g. ${workspaceFolder}/vscode.env

d) import custom_modulename now work for me - in the python interactive window and in a script.

Solution 2

I have a situation that I believe is relatively common. I want a script to import a module from another directory. My python project is laid out as follows:

~/project/
  |
  |---modules/
        |
        |---mod.py
  |---scripts/
        |---script.py

in script.py, I have from modules import mod. So my PYTHONPATH needs to be set to ~/project/ (something that PyCharm does automatically).

VSCode is a great editor, but everywhere else, it falls short, in my opinion. This is a perfect example of that.

I create a default launch.json file to "run the current file". A "cwd": "${fileDirname}" line has to be added to make things work like they do in PyCharm (FYI, a list of the built-in variables can be found here).

Debugging

For debugging (the "play" button on the sidebar, or the F5 key), the PYTHONPATH set in launch.json or your .env file takes effect. Note that in the .env file, you cannot use variables such as ${workspaceRoot}, but you can easily append or insert to the path by using the proper separator for your platform (; for Windows and : for everyone else).

Because I want to take advantage of that variable, I put this in my launch.json:

    "env": {"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"}

(Thanks to @someonr for the suggestion to use ${pathSeparator}.)

It appears that you can prepend/append to whatever is inherited from the environment (this is not true for settings.json; see below).

This will also work for the hotkey Ctrl+F5 (run without debugging).

For reference, here's the full file, which replicates what PyCharm does automatically:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "python",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "cwd": "${fileDirname}",
            "env": {"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"}
        }
    ]
}

Run in terminal

If I hit the "play" button that appears on the top right of the editor window (when a python file is the active tab), it will not work. This runs the current file in a terminal, which doesn't pay attention to launch.json at all. To make that work, you have to define PYTHONPATH in a settings.json file, by adding this:

    "terminal.integrated.env.osx": {"PYTHONPATH": "${workspaceFolder}"}

(Note there are different values for each platform.) If you've selected a python interpreter (e.g. from a virtual environment), you will already have a settings.json file in the .vscode directory. Mine looks like this:

{
    "python.pythonPath": "/Users/me/project/venv/bin/python3",
    "terminal.integrated.env.osx": {"PYTHONPATH": "${workspaceFolder}"}
}

You can't append or insert values into the inherited PYTHONPATH via the settings.json file. It will only take one string, and it will not parse separators. So even though you could get the value using ${env:PYTHONPATH}, you won't be able to do anything with it.

Moreover, you can't set the current working directory. Even though it would seem you could set it with "terminal.integrated.cwd": "${workspaceFolder}", it doesn't work. So if any of your scripts do anything with paths relative to their location in the tree, they won't work. The working directory will be your project root.

Note that any changes to the settings.json file will require that you exit the integrated terminal and restart it.

Linting

Nothing I do to launch.json regarding PYTHONPATH makes any difference to pylint, which will red-underline from modules import mod, despite the fact I can put the cursor on mod, hit F12, and the file opens. Snooping around linting settings, the defaults for mypy include --ignore-missing-imports. To replicate this behavior with pylint, add this to your settings.json:

    "python.linting.pylintArgs": [
        "--disable=F0401"
    ] 

Shame that we just have to work around this, but the autocomplete helps a lot when writing the import statements to begin with.

Conclusion

There are many layers to VSCode and it's hard to get things to work together. It seems multiple environments are floating around. In the end:

  1. I cannot "run in terminal" because I can't set the current working directory to be the path containing the current file.
  2. I cannot set PYTHONPATH for pylint as that runs in some environment different than the integrated terminal and whatever is controlled by launch.json, so I can only tell pylint to ignore import errors.
  3. Running with F5 works if you set PYTHONPATH either via an .env file or in launch.json

Solution 3

This question deserves an upvote because the documentation is missing some important details.

Example

Suppose your project layout is like this

myproject/
    .vscode/
        settings.json
    .env
    src/
        a_module.py
    tests/
        test_a.py

Open the settings.json fie and insert these lines

"terminal.integrated.env.windows": {
    "PYTHONPATH": "${workspaceFolder}/src;${workspaceFolder}/tests"
},
"python.envFile": "${workspaceFolder}/.env",

Note that ${workspaceFolder} evaluates to myproject, it is not to the .vscode folder.

In the .env file enter this

WORKSPACE_FOLDER=C:/full/path/to/myproject
PYTHONPATH=${WORKSPACE_FOLDER}/src;${WORKSPACE_FOLDER}/tests

Note that on Windows the slashes in the path lean forward, like so /. Different paths are separated with a ; (on other platforms with a :).

This blog was helpful.

Solution 4

Setting PYTHONPATH in .env works for me. Note that the effect just is for vscode and the tools it runs, such as pylint.

My situation: I have a project that is not a pip installable package, but simply a source folder. (For historical reasons...)

myproject/src

The project has dependencies defined in a pip requires file.

My setup:

  1. I create a virtualenv, and install the packages from the requires file.
  2. I open vscode in the folder myproject - so this becomes the root of the vscode "project".
  3. I point vscode to use the virtualenv as the python interpreter. This will make imports of dependencies installed with pip work. (For linters, intellisense, etc)
  4. To also make imports from my project source work for the linters (pylint especially) in vscode, I add a .env with this content, adding my project source folder to the PYTHONPATH:
PYTHONPATH=./src:${PYTHONPATH}

Solution 5

For tools like Pyright you can edit python.analysis.extraPaths in the workspace settings.json.

Example:

{
    ...
    "python.analysis.extraPaths": [
        "src/apps",
        "src/override_apps"
    ],
    ...
    // next lines can be different
    "python.linting.enabled": true, 
    "python.linting.pylintEnabled": true,
    "python.linting.mypyEnabled": false,
    "python.pythonPath": "environment/bin/python",
    ...
}
Share:
111,772
Zababa
Author by

Zababa

Updated on July 05, 2022

Comments

  • Zababa
    Zababa almost 2 years

    How do I correctly set up the $PYTHONPATH variable for my workspace in VisualStudio Code?

    Background Information

    I have installed two versions of GNURadio:

    1. GNURadio version 3.7.11 installed by the Linux Mint package manager in /usr/lib/python2.7/dist-packages/gnuradio

    2. GNURadio version 3.7.13.4 installed by PyBOMBS in /home/tejul/Documents/gr13/default/lib/python2.7/dist-packages/gnuradio (my prefix directory is ~/Documents/gr13/default)

    I can use the newer version of GNURadio version only after I run the setup_env.sh script (which -- among other things -- adds /home/tejul/Documents/gr13/default/lib/python2.7/dist-packages to $PYTHONPATH) and then start python in the terminal

    tejul@Wacom:~/Documents/gr13/default$ ls
    bin  etc  include  lib  libexec  setup_env.sh  share  src
    tejul@Wacom:~/Documents/gr13/default$ source ./setup_env.sh 
    tejul@Wacom:~/Documents/gr13/default$ python
    Python 2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
    [GCC 7.3.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from gnuradio import gr
    >>> gr.version()
    '3.7.13.4'
    >>> 
    

    Without modifying the $PYTHONPATH python -- naturally -- imports the older version of GNURadio.

    I want to write, run, and debug python scripts for the new version of GNURadio in the VisualStudio Code. I've been trying to understand the selection of python interpreters, workspaces, and environments for VSCode.

    As far as I understand it, the VSCode workspace setting python.pythonPath is not to be confused with the environment variable $PYTHONPATH. python.pythonPath is the path to the python interpreter used for debugging or running the code, while $PYTHONPATH is the environment variable which python uses to search for modules.

    It looks like PyBOMBS did not install its own python interpreter into my prefix directory. So I need to use VSCode with my normal python interpreter located in /usr/bin/python2.7. So redefining VSCode's python.pythonPath or selecting another python interpreter would not help me.

    I need to let VSCode use my own version of the environment variable $PYTHONPATH which would tell my regular python interpreter to import modules preferably from /home/tejul/Documents/gr13/default/lib/python2.7/dist-packages.

    Problem

    Following the documentation, I have created my own .env file in the workspace directory which sets the order of preference for locations from which python should import the modules. Alas, it has no effect on the python interpreter.

    Showing that VSCode is ignoring my $PYTHONPATH setting

    Can you see anything that I am doing wrong here? I have also tried:

    • Setting the PYTHONPATH to one folder level higher, i.e. /home/tejul/Documents/gr13/default/lib/python2.7, this did not help
    • Calling the variable $PYTHONPATH instead of PYTHONPATH, this did not help
    • Restarting VSCode after each change of the .env file, this did not help
    • Using double quotes around the path string, e.g. PYTHONPATH="/home/tejul/Documents/gr13/default/lib/python2.7:/usr/lib/python2.7", this did not help
  • ARF
    ARF about 5 years
    Please note: On Windows you MUST use semi-colons ';' as separator! PYTHONPATH definitions in env-files are not platform independent: code.visualstudio.com/docs/python/… It took me much too long to figure this out myself the hard way...
  • Lawrence
    Lawrence almost 4 years
    This worked for me to set PYTHONHASHSEED to a fixed value before opening VSCode. I put "python.envFile": "${workspaceFolder}/.env" in the settings.json file like you described and simply added PYTHONHASHSEED="0" to the .env file. Thank you! I have been trying to figure this out for a very long time.
  • Tim Ludwinski
    Tim Ludwinski over 3 years
    after spending the better part of a day trying to get linting to work in a Multi-Root Workspace, I found that for the "python.envFile" setting, setting this in the Workspace config file (ie .code-workspace file) doesn't work but setting this (using your example) in scripts/.vscode/settings.json does the trick. You'll want to note that ${workspaceFolder} will be relative to the scripts folder. Anyway, I think that's what's going on... it's currently working for me.
  • Tim Ludwinski
    Tim Ludwinski over 3 years
    Also, I'm now noticing that the PYTHONPATH in the .env file must be absolute paths (or maybe relative to something but I'm not sure what).
  • Imad
    Imad over 3 years
    Thank you so much for this. I can debug but could NOT understand why running from the terminal was giving me ModuleNotFoundError. Do you have any leads on how/when VScode will be able to function normally across these settings?
  • Imad
    Imad over 3 years
    I've set up my PYTHONPATH to have multiple directories. And for this, I think I cannot put a cursor on my imports, nor can I follow their definitions.
  • mherzog
    mherzog over 3 years
    There is also running of notebooks (and iPython) which seems to be another config task.
  • mike01010
    mike01010 over 3 years
    pylint does not complain if i use the .env file, then restart vscode. it sucks that we have to restart..but it does work it seems.
  • mcoolive
    mcoolive about 3 years
    mypy ignores PYTHONPATH. You can use MYPYPATH instead. See github.com/python/mypy/issues/638
  • Tyler2P
    Tyler2P almost 3 years
    Could you provide more information? What does that code do?
  • darda
    darda almost 3 years
    Now I'm working a lot with IPython (creating cells with the # %% comment) and the easiest solution I've come up with is to add import sys; sys.path.insert(0, sys.prefix + '/../') or similar at the top of the script. This adds one directory up from the Python interpreter's location to the Python path, so it works great if you have a virtual environment as a subdir of ~/project
  • Jason Li
    Jason Li over 2 years
    I had a issue with "from pandas import Excelwriter". It thrown an error "ModuleNotFoundError: No model named 'pandas'. I follow exactly the same way. In the terminal run "which python". It returns the absolute path. Then add this path to the location of python interpreter. This solved my issue. Thanks a lot @SIDHARTH Kumar
  • terwxqian
    terwxqian over 2 years
    in launch.json: add "env": {"PYTHONPATH": "${workspaceFolder}${pathSeparator}${env:PYTHONPATH}"} this one works for me on win11-vscode.
  • wisbucky
    wisbucky over 2 years
    I thought that vscode .env file doesn't do variable expansion like ${WORKSPACE_FOLDER}? "Variable substitution is only supported in VS Code settings files, it will not work in .env environment files."
  • wisbucky
    wisbucky over 2 years
    @someonr ${pathSeparator} is not : or ;. ${pathSeparator} is / for Linux/Mac or \ for Windows (source). Unfortunately, VS Code does not have a variable for : or ;, so .env PYTHONPATH= can't be cross platform if it has multiple entries. That's why I use pylint's --init-hook to prepend sys.path instead.
  • wisbucky
    wisbucky over 2 years
    @darda You shouldn't disable pylint's missing import error. I know it's not easy, but it is fixable. You have to play around with adding __init__.py files, and setting sys.path properly. Either with PYTHONPATH or --init-hook "import sys, os; sys.path.insert(0, os.path.join('src', 'foo'))"
  • MathKid
    MathKid over 2 years
    On that same page it says: "values can refer to any other environment variable that's already defined in the system or earlier in the file", which is what we're doing here. It seems the documentation is contradicting itself.
  • someonr
    someonr over 2 years
    @wisbucky Thx! I deleted my misleading comment. Sorry for the confusion
  • Vitamin C
    Vitamin C over 2 years
    Still doesn't help, ModuleNotFoundError remains(
  • Darshan Bhat
    Darshan Bhat about 2 years
    For linting you can edit "settings.json" and add ""python.autoComplete.extraPaths". Here you can mention the additional path to be scanned.
  • Veb
    Veb about 2 years
    I have two virtual environments, one for src and one for test, how to get that working? Also, I am confused about the workspace folder. In settings.json you are using workspaceFolder but in .env, you are using WORKSPACE_FOLDER. How will that work?