VSCode 1.39.x & Python 3.7.x: "ImportError: attempted relative import with no known parent package" - when started without debugging (CTRL+F5))
Asked Answered
D

5

21
  • when running Python test from withing VS Code using CTRL+F5 I'm getting error message

    ImportError: attempted relative import with no known parent package

Error message text: "ImportError: attempted relative import with no known parent package"

  • when running Python test from VS Code terminal by using command line

    python test_HelloWorld.py

    I'm getting error message

    ValueError: attempted relative import beyong top-level package

Error Message: "ValueError: attempted relative import beyond top-level package"

Here is the project structure

Project structure

How to solve the subject issue(s) with minimal (code/project structure) change efforts?

TIA!

[Update]

I have got the following solution using sys.path correction:

The subject issue solution using sys.path correction

import sys
from pathlib import Path
sys.path[0] = str(Path(sys.path[0]).parent)

but I guess there still could be a more effective solution without source code corrections by using some (VS Code) settings or Python running context/environment settings (files)?

Discordant answered 5/11, 2019 at 11:2 Comment(0)
M
7

Do not use relative import. Simply change it to

from solutions import helloWorldPackage as hw

Update

I initially tested this in PyCharm. PyCharm has a nice feature - it adds content root and source roots to PYTHONPATH (both options are configurable).

You can achieve the same effect in VS Code by adding a .env file:

PYTHONPATH=.:${PYTHONPATH}

Now, the project directory will be in the PYTHONPATH for every tool that is launched via VS Code. Now Ctrl+F5 works fine.

Marrissa answered 5/11, 2019 at 11:26 Comment(3)
Thank you for your answer. The proposed code correction results in ModuleNotFoundError: No module named 'solutions' error message.Discordant
I could be doing something wrong - I have added .env file with proposed PYTHONPATH option and corrected import statement. Still getting "ModuleNotFoundError: No module named 'solutions'" error message.Discordant
The answer about .env file change could be improved with a reminder to use semicolon as a separator instead of colon, in case there are still some developers who use Windows operating system.Monstrosity
T
6

You're bumping into two issues. One is you're running your test file from within the directory it's written, and so Python doesn't know what .. represents. There are a couple of ways to fix this.

One is to take the solution that @lesiak proposed by changing the import to from solutions import helloWorldPackage but to execute your tests by running python tests/test_helloWorld.py. That will make sure that your project's top-level is in Python's search path and so it will see solutions.

The other solution is to open your project in VS Code one directory higher (whatever directory that contains solutions and tests). You will still need to change how you execute your code, though, so you are doing it from the top-level as I suggested above.

Even better would be to either run your code using python -m tests.test_helloWorld, use the Python extension's Run command, or use the extension's Test Explorer. All of those options should help you with how to run your code (you will still need to either change the import or open the higher directory in VS Code).

Thoria answered 5/11, 2019 at 22:58 Comment(2)
Thank you for your suggestion. It didn't work for me. I will keep trying to fix the issue using your guideline.Discordant
It is not intutive to open the project in VS Code one directory higher , but this worked for me . Thanks!Fontenot
S
2

Setup a main module and its source packages paths

Solution found at:

Which also provide a neat in-depth video explanation


The solution to the attempted relative import with no known parent package issue, which is especially tricky in VScode (compared to tools such as Pycharm that provide GUI tools to flag folders as package), is to:

Add configuration files for the VScode debugger

Id Est add launch.json as a Module (this will always execute the file given as the value of the "module" key) and settings.json inside the MyProjectRoot/.vscode folder (manually add them if it's not there yet, or be guided by VScode GUI for Run & Debug)

launch.json setup

Id Est add an "env" key to launch.json containing an object with "PYTHONPATH" as key, and "${workspaceFolder}/mysourcepackage" as value
final launch.json configuration

settings.json setup

Id Est add a "python.analysis.extraPaths" key to settings.json containing a list of paths for the debugger to be aware of, which in our case is one ["${workspaceFolder}/mysourcepackage"] as value (note that we put the string in a list only for the case in which we want to include other paths too, it is not needed for our specific example but it's still a standard de facto as I know)
final settings.json configuration

This should be everything needed to both work by calling the script with python from the terminal and from the VScode debugger.

Spelldown answered 11/6, 2022 at 15:29 Comment(0)
H
1

An Answer From 2022

Here's a potential approach from 2022. The issue is identified correctly and if you're using an IDE like VS Code, it doesn't automatically extend the python path and discover modules.

One way you can do this using an .env file that will automatically extend the python path. I used this website k0nze.dev repeatedly to find an answer and actually discovered another solution.

Here are the drawbacks of the solution provided in the k0nze.dev solution:

  • It only extends the python path via the launch.json file which doesn't effect running python outside of the debugger in this case
  • You can only use the ${workspaceFolder} and other variables within an "env" variable in the launch.json, which gets overwritten in precedence by the existence of a .env file.
  • The solution works only within VS Code since it has to be written within the launch.json (- overall portability)

The .env File

In your example tests falls under it's own directory and has it's own init.py. In an IDE like VS Code, it's not going to automatically discover this directory and module. You can see this by creating the below script anywhere in your project and running it:

_path.py

from sys import path as pythonpath

print("\n ,".join(pythonpath))

You shouldn't see your ${workspaceFolder}/tests/ or if you do, it's because your _path.py script is sitting in that directory and python automatically adds the script path to pythonpath. To solve this issue across your project, you need to extend the python path using .env file across all files in your project.

To do this, use dot notation to indicate your ${workspaceFolder} in lieu of being able to actually use ${workspaceFolder}. You have to do dot notation because .env files do not do variable assignment like ${workspaceFolder}. Your env file should look like:

Windows

PYTHONPATH = ".\\tests\\;.\\" 

Mac / Linux / etc

PYTHONPATH = "./tests/:./"

where:

  • ; and : are the path separators for environment variables for windows and Mac respectively
  • ./tests/ and .\tests\ extend python path to the files within the module tests for import in the init.py
  • ./ and .\ extend the python path to modules tests and presumably solutions? I don't know if solutions is a module but I'm going to run with it.

Test It Out

Now re-run your _path.py script and you should see permanent additions to your path. This works for deeply nested modules as well if your company has a more stringent project structure.

VS Code

If you are using VS Code, you cannot use environment variables provided by VS Code in the .env file. This includes ${workspaceFolder}, which is very handy to extend a file path to your currently open folder. I've beaten myself up trying to figure out why it's not adding these environment variables to the path for a very long time now and it seems

The solution is instead to use dot notation to prepend the path by using relative file path. This allows the user to append a file path relative to the project structure and not their own file structure.

For Other IDE's

The reason the above is written for VS Code is because it automatically reads in the .env file every time you run a python file. This functionality is very handy and unless your IDE does this, you will need the help of the dotenv package.

You can actually see the location that your version of VS Code is looking for by searching for the below setting in your preferences:

VSCode settings env file

Anyways, to install the package you need to import .env files with, run:

pip install python-dotenv

In your python script, you need to run and import the below to get it to load the .env file as your environment variables:

from dotenv import load_dotenv()

# load env variables 
load_dotenv()

"""
The rest of your code here
"""

That's It

Congrats on making it to the bottom. This topic nearly drove me insane when I went to tackle it but I think it's helpful to be elaborate and to understand the issue and how to tackle it without doing hacky sys.path appends or absolute file paths. This also gives you a way to test what's on your path and an explanation of why each path is added in your project structure.

Haematosis answered 10/8, 2022 at 13:41 Comment(0)
Y
0

I was just going through this with VS Code and Python (using Win10) and found a solution. Below is my project folder. Files in folder "core" import functions from folder "event", and files in folder "unit tests" import functions from folder "core".

I could run and debug the top-level file file_gui_tk.py within VS Code but I couldn't run/debug any of the files in the sub-folders due to import errors. I believe the issue is that when I try to run/debug those files, the working directory is no longer the project directory and consequently the import path declarations no longer work.

Folder Structure:

testexample
    core
        __init__.py
        core_os.py
        dir_parser.py
    events
        __inits__.py
        event.py
    unit tests
        list_files.py
        test_parser.py
.env
file_gui_tk.py

My file import statements:

in core/core_os.py:

 from events.event import post_event

in core/dir_parser.py:

from core.core_os import compare_file_bytes, check_dir
from events.event import post_event

To run/debug any file within the project directory, I added a top level .env file with contents:

PYTHONPATH="./"  

Added this statement to the launch.json file:

"env": {"PYTHONPATH": "/testexample"},

And added this to the settings.json file

"terminal.integrated.env.windows": {"PYTHONPATH": "./",}

Now I can run and debug any file and VS Code finds the import dependencies within the project.

I haven't tried this with a project dir structure more than two levels deep.

Yeung answered 3/12, 2022 at 15:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.