Reputation: 1594
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
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
Here is the 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:
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)?
Upvotes: 24
Views: 32284
Reputation: 51
Same as what mentioned in this answer by Scott.
I was looking for how to solve this issue of relative paths. This article showed to me how it is done. https://k0nze.dev/posts/python-relative-imports-vscode/
So you need to use the "env"
key in launch.json to add your workspace directory to the PYTHONPATH
and voila!
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Module",
"type": "python",
"request": "launch",
"program": "${file}",
"env": {"PYTHONPATH": "${workspaceFolder}"}
}
]
}
Upvotes: 0
Reputation: 41
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:
Id Est add
launch.json
as aModule
(this will always execute the file given as the value of the "module" key) andsettings.json
inside theMyProjectRoot/.vscode
folder (manually add them if it's not there yet, or be guided by VScode GUI forRun & Debug
)
launch.json
setupId Est add an
"env"
key tolaunch.json
containing an object with"PYTHONPATH"
as key, and"${workspaceFolder}/mysourcepackage"
as value
final launch.json configuration
settings.json
setupId Est add a
"python.analysis.extraPaths"
key tosettings.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.
Upvotes: 2
Reputation: 11
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.
Upvotes: 1
Reputation: 11
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:
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:
PYTHONPATH = ".\\tests\\;.\\"
PYTHONPATH = "./tests/:./"
where:
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.
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.
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:
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
"""
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.
Upvotes: 1
Reputation: 26074
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.
Upvotes: 7
Reputation: 16080
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).
Upvotes: 6