dash-labs icon indicating copy to clipboard operation
dash-labs copied to clipboard

Multi Page Apps: circular reference when importing app

Open stevej2608 opened this issue 3 years ago • 10 comments

I define my dash app instance in app.py:

server = flask.Flask(__name__)
app = Dash(__name__,
        plugins=[dl.plugins.pages],
        external_stylesheets=external_stylesheets,
        external_scripts=external_scripts, server=server)

By default the pages plug-in iterates over the modules in the ./pages folder. I have a page that needs to reference the dash app instance in order to call the get_asset_url() method.

In my page module, the import:

from app import app

Creates a circular reference. I can fix this with an embedded import but I'd prefer not to. Is there a way to resolve this? Ideally a proxy reference to the current dash instance (dash.current_app) would be one solution.

Cheers.

stevej2608 avatar Dec 18 '21 12:12 stevej2608

@stevej2608

It's true that importing app within the pages folder will create a circular reference. I'll look into adding a proxy reference, but in the meantime, to access items in assets, rather than using app.get_assets_url() could you try adding the path? For example: html.Img(src="/assets/my_image.jpeg"). It worked for me when I tried it.

AnnMarieW avatar Dec 18 '21 17:12 AnnMarieW

First of all, BIG thank you for this module. It's been a lot of fun to learn and play with.

Is there a suggested workaround for calling the get_relative_path() method? Similar to what @stevej2608 mentioned, I get a circular reference when trying to run from app import app, but I need the relative path because the platform I'm looking to host my app on applies a unique prefix for the app (guid generated during deployment). Because of this, I can't know the path name when deploying until I've deployed the app at least once. The platform does recognize that the prefix exists as a variable and has the correct value, but I can't figure out a way to pass the requests_pathname_prefix to the modules in the /pages folder.

M4thM4gician avatar Jan 25 '22 22:01 M4thM4gician

@M4thM4gician Glad you like pages/

We definitely need to be able to accommodate this use case. Thanks for reporting. I'll keep you posted on the progress.

AnnMarieW avatar Jan 26 '22 00:01 AnnMarieW

@stevej2608, @M4thM4gician To solve the circular reference issue we will be adding the following functions that will be similar to dash.callback where the appobject is not needed. This is on the project plan to be completed before pages/ is moved into Dash.

  • dash.get_relative_path
  • dash.strip_relative_path
  • dash.get_asset_url

This is a good first issue. Here are some tips for getting started:

  • The pull request will be in dash, rather than here in dash-labs
  • The solution will be similar to how dash.callback was created. Here is the pull request

Related issues:

Are there plans to integrate a solution to accessing the cache in callbacks outside the app.py file? For example, I have multipage app that uses a structure similar to the “Caching and Signaling” example in the docs. Once the expensive query is complete, callbacks on every page will be utilizing this same data source and need to access the global cache. Since the cache is tied to the app object, I haven’t been able to make this work on a multipage setup without just putting all my callbacks inside the app.py file. This quickly becomes hard to navigate with a larger multipage app.

AnnMarieW avatar Jan 27 '22 23:01 AnnMarieW

@AnnMarieW That is REALLY exciting! Thank you so much for following up on this and for the quick responses. I'm looking forward to using this new capability to build beautiful content using Dash and Dash Labs!

M4thM4gician avatar Jan 28 '22 14:01 M4thM4gician

PR: https://github.com/plotly/dash/pull/1923

AnnMarieW avatar Feb 14 '22 14:02 AnnMarieW

Should a new issue be opened up for the caching issue detailed here?

Are there plans to integrate a solution to accessing the cache in callbacks outside the app.py file? For example, I have multipage app that uses a structure similar to the “Caching and Signaling” example in the docs. Once the expensive query is complete, callbacks on every page will be utilizing this same data source and need to access the global cache. Since the cache is tied to the app object, I haven’t been able to make this work on a multipage setup without just putting all my callbacks inside the app.py file. This quickly becomes hard to navigate with a larger multipage app.

bigmike36c avatar Feb 16 '22 17:02 bigmike36c

Reopening this issue - PR#1923 created:

  • dash.get_relative_path
  • dash.get_asset_url
  • dash.strip_relative_path

As described above, the following is still open: Caching and Signaling app.long_callback

AnnMarieW avatar Feb 16 '22 17:02 AnnMarieW

Just to add to this, the same issue occurs with the dashboard engine for enterprise users. The workaround is easy enough by simply registering the dashboard engine page and declaring its layout inside the app.py file. However, for code organization, it would be nice to eventually be able to break this code and the associated callbacks into its own file.

bigmike36c avatar Feb 24 '22 22:02 bigmike36c

Thanks for reporting @bigmike36c ! Yes agreed re dashboard engine. We'll need to make an update to that library that doesn't require app as an input argument as well. That's becoming easier with dash.callback and other properties, so we're close.

chriddyp avatar Feb 25 '22 00:02 chriddyp