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:
- I cannot "run in terminal" because I can't set the current working directory to be the path containing the current file.
- I cannot set
PYTHONPATHforpylintas that runs in some environment different than the integrated terminal and whatever is controlled bylaunch.json, so I can only tellpylintto ignore import errors. - Running with F5 works if you set
PYTHONPATHeither via an.envfile or inlaunch.json
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:
- I cannot "run in terminal" because I can't set the current working directory to be the path containing the current file.
- I cannot set
PYTHONPATHforpylintas that runs in some environment different than the integrated terminal and whatever is controlled bylaunch.json, so I can only tellpylintto ignore import errors. - Running with F5 works if you set
PYTHONPATHeither via an.envfile or inlaunch.json
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 file and insert these lines
// On linux use "terminal.integrated.env.linux": {
"terminal.integrated.env.windows": {
"PYTHONPATH": "${workspaceFolder}/src;${workspaceFolder}/tests"
},
// The next line can be omitted, unless you've modified the global default
"python.envFile": "${workspaceFolder}/.env",
Note that ${workspaceFolder} evaluates to myproject, it is not to the .vscode folder.
In the .env file enter this
PYTHONPATH=src;test
# Paths are relative to the workspace folder, so above is equivalent to
# WORKSPACE_FOLDER=C:/full/path/to/myproject
# PYTHONPATH=${WORKSPACE_FOLDER}/src;${WORKSPACE_FOLDER}/tests
Note that on all platforms, including Windows, the slashes in the path lean forward, like so /. Different paths are separated with a ; on Windows, on other platforms with a :.
Final step, restart VS Code.
This blog was helpful.
Automatically set pythonpath correctly for default project setups
Feature Request: Easily Add Folder to PYTHONPATH from VS Code UI
Change PYTHONPATH before debug
Visual Studio Code - How to add multiple paths to python path? - Stack Overflow
Videos
I want to be able to have a separate dir for my test suite (which have imports from the source code). My source modules have imports that reference other files in the same directory and it works when I run that code, but when I try to run the test suite, VSCode can't find the modules. For some reason running the test suite works in PyCharm, and I've been trying to figure out the behavior in Pycharm so I could change the behavior accordingly in VSCode to no avail, and figured someone here would know. I'm trying to use VSCode instead of PyCharm because the project also has React/JS and I don't even know if PyCharm would support that (and I just like VSCode better in general... except for this annoying thing).
My directory structure is as follows:
app
|____init__.py
|__client
|__server
|____init__.py
|___.venv
|___data
|___lib
|____init__.py
|___config.ini
|___config_reader.py
|___sql_connection.py (imports config_reader and passes in 'lib/config.ini' to the reader function)
|___tests
|____init__.py
|___testconfig.ini
|___test_sql_connection.py (i try to import config_reader here but vscode will say that the module doesn't exist)Does anyone have any advice?
EDIT: added that i do have init.py in my folders
This worked for me:-
in your launch.json profile entry, specify a new entry called "env", and set PYTHONPATH yourself.
"configurations": [
{
"name": "Python",
"type": "python",
"stopOnEntry": false,
"request": "launch",
"pythonPath": "${config.python.pythonPath}",
"program": "${file}",
"cwd": "${workspaceRoot}",
"debugOptions": [
"WaitOnAbnormalExit",
"WaitOnNormalExit",
"RedirectOutput"
],
"env": {
"PYTHONPATH": "/path/a:path/b"
}
}
]
The Python Extension in VS Code has a setting for python.envFile which specifies the path to a file containing environment variable definitions (Refer to: https://code.visualstudio.com/docs/python/environments#_environment-variable-definitions-file). By default it is set to:
"python.envFile": "${workspaceFolder}/.env"
So to add your external libraries to the path, create a file named .env in your workspace folder and add the below line to it if you are using Windows:
PYTHONPATH="C:\path\to\a;C:\path\to\b"
The advantage of specifying the path here is that both the auto-complete as well as debugging work with this one setting itself. You may need to close and re-open VS Code for the settings to take effect.
For the current python path, you need to select an interpreter and the currently used one is shown as a relative path in the box.

In tasks, have args called options so you can define env and PYTHONPATH there

You can find more details about tasks from the Tasks in Visual Studio Code documentation.
If you have the Python VSCode extension installed, and an interpreter is selected, then you can get the path to that interpreter in tasks.json using ${command:python.interpreterPath}.