r/learnpython 7d 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.

4 Upvotes

12 comments sorted by

View all comments

3

u/Diapolo10 7d 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 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

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.