mickzer
mickzer

Reputation: 6358

Python import from parent package

I'm having some trouble with imports in Python.

Here is a simple example of what's going wrong.

I have a directory structure like this:

app
|---__init__.py
|---sub_app
    |---__init__.py

The code:

app/__init__.py

shared_data = {
    'data': 123
}

from sub_app import more_shared_data
print more_shared_data

app/sub_app/__init__.py

more_shared_data = {
    'data': '12345'
}
from app import shared_data
print shared_data

However I get the error:

ImportError: No module named app

How do I import the shared_data dict, into app/sub_app/__init__.py?

Upvotes: 5

Views: 4864

Answers (2)

Dunes
Dunes

Reputation: 40853

You have a few problems here, one of which is hidden.

It looks like you are trying to invoke your program like:

python app/__init__.py
python app/sub_app/__init__.py

This causes problems in that the directory of the main file is considered to be the root directory of the program. That is, why sub_app cannot see app.

You can instead invoke your programs like such

python -m app.sub_app

This way python assumed the current directory is the root directory and looks for the module app.sub_app under this directory. This causes another problem though. To be able to run a package you need to provide a __main__.py in the package (as well as __init__.py). If the modules do not import each other, then order of invocation will be app/__init__.py, app/sub_app/__init__.py, and then app/sub_app/__main__.py

app
|---__init__.py
|---sub_app
    |---__init__.py
    |---__main__.py

app/sub_app/__main__.py can do stuff like:

from app import shared_data
from . import more_shared_data
# or
from app.sub_app import more_shared_data

Finally, the hidden problem is that you have circular imports. That is, app depends on sub_app and sub_app depends on app. That both app and sub_app need the other to be loaded, before they can load -- this is of course impossible. You should refactor your code to avoid circular imports.

Upvotes: 2

Anand S Kumar
Anand S Kumar

Reputation: 91009

You can use relative imports for this . Example -

In your app/sub_app/__init__.py -

more_shared_data = {
    'data': '12345'
}
from .. import shared_data
print shared_data

This should work for the simple example you have provided , but it does lead to circular import , app is importing sub_app and sub_app is importing app .

For more complex usecases, you can end up with errors (If you import sub_app) before defining specific elements, and then in sub_app/__init__.py you try to import app and use those elements that are only defined after the import statement for sub_app . A very simple example where it would cause issue -

app/__init__.py -

from .sub_app import more_shared_data
print(more_shared_data)

shared_data = {
    'data': 123
}

app/sub_app/__init__.py -

more_shared_data = {
    'data': '12345'
}
from .. import shared_data
print(shared_data)

Now, if you try to import app , you will get the error -

>>> import app
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<some file>\__init__.py", line 1, in <module>
    from .shared import more_shared_data
  File "<some file>\sub_app\__init__.py", line 4, in <module>
    from .. import shared_data
ImportError: cannot import name 'shared_data'

You should re-think if shared_data does belong to app/__init__.py , or it can be moved to sub_app/__init__.py and then imported from there in app .

Upvotes: 2

Related Questions