2

Problem

In a Python project with subpackages, absolute imports don't work inside any files that aren't in the project root directory.

-  my_project
  -  my_package
    - __init__.py
    - my_module.py
  - my_scripts
    - some_script.py

some_script.py

import sys
print('\n'.join(sys.path))

from my_package.my_module import hello_world
hello_world()

Output (PyCharm)

D:\_MyFiles\Programming\Projects\python-import-demo\my_scripts
D:\_MyFiles\Programming\Projects\python-import-demo
***list of unrelated paths***

Hello, World!

Output (VS Code)

d:\_MyFiles\Programming\Projects\python-import-demo\my_scripts
***list of unrelated paths***

Traceback (most recent call last):
  File "d:\_MyFiles\Programming\Projects\python-import-demo\my_scripts\some_script.py", line 4, in <module>
    from my_package.my_module import hello_world
ModuleNotFoundError: No module named 'my_package'

Workarounds

  • Use relative imports (this breaks __main__ blocks)
  • Edit project-level launch.json config (the problem still happens when running .py files through the top bar or CLI)
  • Run pip install -e MY_PROJECT (I don't want to repeat this for every project I open)
  • Explicitly find the project root directory and append it to sys.path inside my own code (this is disgusting in my opinion, but good if I want to send the project to someone and have it simply work with no additional configuration by them)

I found all these workarounds here and here

Question

Is there any way to solve this problem for VS Code globally? When I open a project in PyCharm and run any .py file, absolute imports just work automatically without any manual configuration because the project root gets added to sys.path and that's what I want for VS Code. I don't want to have to use any of the above workarounds on every new project.

pyjamas
  • 4,608
  • 5
  • 38
  • 70
  • "Run pip install -e MY_PROJECT (I don't want to repeat this for every project I open)" why don't you want to do this? This is the *correct way* – juanpa.arrivillaga Apr 11 '23 at 22:51
  • It just seems like an extra unnecessary step of boilerplate. Also in cases where I don't create a `venv` I'm polluting the `pip` package namespace with project folder names which might cause name collisions if I'm not careful. I realize using a `venv` is the *correct* way but I do a lot of one-off data analysis tasks and don't want to fill my hard drive with gigabytes of identical installations of pandas and pytorch. – pyjamas Apr 11 '23 at 23:26
  • 1
    You should *absolutely be creating virtual environments too!* The great thing about them is that they are *cheap*. You can *just delete them* and *reinstall them* as needed. And if you use something like conda, it actually shares compatible installs. Anyway, I upvoted your answer since I still think this is a valid question and it is a good answer – juanpa.arrivillaga Apr 11 '23 at 23:27

2 Answers2

3

Fixed it by adding this to settings.json

  "terminal.integrated.env.windows": {
    "PYTHONPATH": "${workspaceFolder}"
  }
pyjamas
  • 4,608
  • 5
  • 38
  • 70
0

Yet another way to set the PYTHONPATH in Visual Studio Code is to find your workspace folder (folder that you opened from the file menu to find your source code). This folder name turns into upper case letters in the Explorer (source code) panel in Visual Studio Code. Then create a file in that folder called "name_this_whatever.env". I usually call this "workspace.env". Wherever you have a new root source code folder, you will need a new .env file. Set the PYTHONPATH environment variable in the .env file. This assumes the Python extension in Visual Studio Code is installed. By default, this Visual Studio Code extension automatically looks at ${workspaceFolder}/.env. You can see the default configuration by going to Visual Studio Code > File > Settings > Preferences > click on "Python" > find "Env File \n Absolute path to a file containing environment variable definitions. Note that variable expansion is NOT possible in this file unless CMake Tools extension is installed with 1.7 or later. Variable expansion basically says that you can use one variable to set part of or all of another variable. Such as PYTHONPATH=${something}.

Windows:

PYTHONPATH=C:\modules\module1;C:\modules\module2;

Linux:

PYTHONPATH=/opt/modules/module1:/opt/modules/module2:

The value of this PYTHONPATH is a list of paths separated by a semicolon character on Windows platforms, or by a colon character on Unix platforms

JustBeingHelpful
  • 18,332
  • 38
  • 160
  • 245