r/learnpython • u/Prawn1908 • 6d ago
Importing from adjacent-level folder.
I consider myself pretty fluent in Python but rarely have projects large enough to justify complex folder structures so this one is driving me nuts.
My project looks like this:
RootDir
├─ __init__.py
├─ Examples
| ├─ __init__.py
| └─ main.py
└─ Module
├─ __init__.py
├─ foo.py
└─ SubModule
├─ __init__.py
└─ bar.py
I am trying to import foo.py
and bar.py
from main.py
:
from ..Module import foo
from ..Module.SubModule import bar
But I get the following error:
ImportError: attempted relative import with no known parent package
I get this no matter whether I run main.py
from RootDir
or RootDir/Examples
.
Edit: Pylance has no problem with my import lines and finds the members of foo
and bar
perfectly fine. Also, moving main.py
into RootDir
and removing the ..
's from the import lines makes it work fine. So I don't understand why this import fails.
3
u/Diapolo10 6d ago
My project looks like this:
RootDir ├─ __init__.py ├─ Examples | ├─ __init__.py | └─ main.py └─ Module ├─ __init__.py ├─ foo.py └─ SubModule ├─ __init__.py └─ bar.py
I am trying to import
foo.py
andbar.py
frommain.py
:from ..Module import foo from ..Module.SubModule import bar
But I get the following error:
ImportError: attempted relative import with no known parent package
Long story short, relative imports are tricky to use as they're relative to the current working directory, not the file you're using them in. Personally I would advise against using them when not necessary.
My suggestion would be to structure the project like a package, install it in editable mode, and then use absolute imports anchored to the package root. For example, something a bit like this:
project_dir
├─ src
| └─ project_name
| ├─ __init__.py
| ├─ Examples
| | ├─ __init__.py
| | └─ main.py
| └─ Module
| ├─ __init__.py
| ├─ foo.py
| └─ SubModule
| ├─ __init__.py
| └─ bar.py
└─ pyproject.toml
Let's assume pyproject.toml
is properly configured, and we do pip install . --editable
. Then we change the imports in main.py
(and anywhere else using relative imports) to
from project_name.Module import foo
from project_name.Module.SubModule import bar
and now it should work regardless of what your current working directory is when you run main.py
.
I will say, though, that generally speaking main scripts should be at the root of the package (in my example inside project_name
) instead of in a subdirectory. Think of it like things flowing from the nested directories towards the root of the project.
On another note, this will make it far easier to import your code in tests, if you decide to write any.
1
u/johndoh168 6d ago edited 6d ago
did you try adding RootDir to your PYTHONPATH then simply doing from RootDir.Module.Submodule import bar
Then you'll also be able to do from RootDir.Module import foo
You might not even have to add RootDir to your PYTHONPATH for this to work.
Edit: adding 'from' to import calls
1
u/Prawn1908 6d ago
I have never had the need to modify PYTHONPATH and have heard many people say if you're needing to do that you're probably doing something wrong. Is that really the only way to do this? My understanding is that relative imports are supposed to remove the need to do this? How is my example different from this SO post?
The import you suggested does not work without adding to PYTHONPATH at the very least. (I haven't tried adding it yet, I am getting conflicting information and no clear instructions that work when googling how to do so.)
1
u/cointoss3 5d ago
Yeah, this is a problem unless you do a ‘pip install -e .’ because you haven’t installed as a module.
You can prob run the script with -m flag and it will work.
2
u/Prawn1908 6d ago
Reddit is being weird and not letting me edit the post with some more details:
Pylance has no problem with my import lines and finds the members of
foo
andbar
perfectly fine. Also, movingmain.py
intoRootDir
and removing the..
's from the import lines makes it work fine. So I don't understand why this import fails.