Search code examples
python-3.ximporthierarchy

File hierarchy and local imports


I'm trying to figure out file hierarchy and local imports in python3. I've run into a problem with a file structure below:

└── project
    ├── run.py
    └── scripts
        ├── __init__.py
        ├── misc.py
        ├── script1.py
        └── script2.py

I use relative imports for all files in the "scripts" directory.

from misc import x, y, z

I use absolute imports in run.py.

from scripts.misc import a, b, c
from scripts.script1 import more_stuff

My goal is to have the python files independent and fully functional. However, when I attempt to execute run.py, I encounter an error.

from misc import x, y, z
ModuleNotFoundError: No module named 'misc'

I would expect relative paths to be relative to the original file and not adopt the path of the executed file. Can I fix this by modifying the imports or file structure?

It also appears I don't understand how __init__.py works. I want to re-use generic package names (like "scripts"). I had assumed that __init__.py files would be read immediately downstream relative to the executed file: if run.py is executed, only the scripts directory at the same level should be considered. I have found that a distant (unrelated?) "scripts" directory receives priority. Is this something that can be addressed with more careful absolute paths? Example below.

└── dir
    └── project1
    |   ├── run.py
    |   └── scripts
    |       ├── __init__.py
    |       └── settings.py
    └── subdir
        └── project2
            ├── run.py
            └── scripts
                ├── __init__.py
                └── settings.py

Executing run.py from "project1" will attempt to import the "scripts" directory from project2.

cannot import name 'variable' from 'scripts.settings' (/Users/.../dir/subdir/project2/scripts/settings.py)

Removing __init__.py from project2/scripts no longer produces the error when executing run.py from "project1".


Solution

    1. You are saying:

    I use relative imports for all files in the "scripts" directory.

    from misc import x, y, z

    But this is not relative. For relative you need to have

    from .misc import x, y, z
    
    1. To understand why the unrelated scripts is taking precedence, look on your sys.path and verify if indeed it comes before your scripts package. I can assume the is some leftover for ide path manipulation.