Dash Pages - access content outside pages folder from inside pages folder

When trying out the new Dash Pages, I found that I cannot access modules outside of the pages folder from inside the pages folder via relative imports. Let’s say that I have the following folder structure:

UI/
    common_data/
        styles.py
    pages/
        other_page/
            other_page.py
        home.py
    app.py
    run_my_app.py

Where common_data/styles.py contains some style definitions,

# run_my_app.py
from UI.app import app

app.run(debug=True)

and the other files contain a multi-page app similar to the Dash example.

The problem

From pages/home.py or pages/other_page/other_page.py it is not possible to import common_data/styles.py via relative imports.
For example:

# pages/home.py
from ..common_data import styles

results in the error

ImportError: attempted relative import beyond top-level package

A print statement above the relative import reveals why this is the case:

# pages/home.py
print(f'home: {__name__ = }')
from ..common_data import styles

will print

>>> home: __name__ = 'pages.home'

Clearly showing that the scope of the modules/scripts within the pages folder is restricted to the pages folder.

Note: the same thing happens for pages/other_page/other_page.py where

print(other_page: {__name__ = }')

prints

>>> other_page: __name__ = 'pages.other_page.other_page'

How can I pass the scope of app.py to the individual pages so that I can access content outside of the pages folder via relative imports? I think this happens due to how the Dash page registry searches and loads the contents of the pages folder.

Absolute imports

I know that it is possible to access external content using absolute imports, i.e. replacing the relative import with

from UI.common_data import styles

makes the dashboard work. However due to portability considerations of my dashboard code between different computers, it is much more convenient to use relative imports.

1 Like

I had to do something similar to get mapbox to work since it requires a token. Wound up utilizing pythons os package. Example from mine:

cwd_path = os.path.dirname(__file__)
tkn = open(os.path.join(os.path.split(os.path.dirname(__file__))[0], '*file name*')).read()

This code sits in the actual page itself accessing a file on the root of my project. This should offer some semblance of portability since it dynamically finds the parent folder.

1 Like

Thanks for the suggestion. I didn’t reply before, but I have seen it. I am playing around with my dashboard folder structure to see what works and what doesn’t. If I come to some interesting conclusion, I will share it here.

Has there been any update to this? I’m also experiencing this problem when migrating an existing multi-page Dash app to use Dash Pages.

As of dash 2.8.0 you can do relative imports by using __package__ instead of __name__ in the app constructor. For example:

app = Dash(__package__, use_pages=True)

So, using the file structure given in the original post, the module names for the files in the pages folder would be:

UI.pages.home
UI.pages.other_page.other_page 

This was fixed in dash 2.8 by @nedned 's pull request #2392.
Ned, do you have any other comments?

1 Like

I think you covered all the relevant parts!

@nedned Thanks for your pull request that fixed this issue - and more! :trophy:

1 Like

Thanks @AnnMarieW and @nedned for the awesome work! Really amazing to see that this issue was solved. Life came in the way for me to further develop my app, so I forgot about this issue a bit.

2 Likes

Thanks very much for this solution - it did eventually work for me (although it’s extremely unintuitive that the name of the Dash app is relevant at all for whether it can find relative imports from pages)