Importing a custom module within a callback doesn't load its own callbacks

Ok so, I know you’re thinking “why would you ever wanna do that”, but bear with me for a moment.

I made a web abb that allows users to upload a CSV file, and then takes them to a dashboard that shows some interactive plots.

The app structure is, very simplified, like this:

index.py
views/
    data/
    upload_file.py
    dashboard.py

The index file imports both views at the beginning.

Upload_file.py can have two behaviors, based on a condition: it checks if the data folder contains a compatible file. If it does, it asks the user if they want to continue with the old file or upload a new one. So far so good.

If the data folder is empty, however, it asks the user to upload a file. This is where the problem starts: if data is empty, when dashboard.py gets imported at startup, it runs its code, sees that there’s no data, and returns an error because it can’t load any dataset, of course.

So I tried importing dashboard.py in the callback that loads the dashboard, in pseudocode like this:

@app.callback(
    Output(main_Div),
    Input(url)
)
def load_dashboard(url):
    if url == '/dashboard':
        from views import dashboard
        return dashboard.layout

This technically works, except for one single issue: the callbacks of dashboard.py don’t get loaded in the app, and therefore when the dashboard gets loaded, all plots are empty because there’s no callback to update them.
Surprisingly, clicking reload on the browser then makes it so that all callbacks get imported and the dashboard loads its plots properly.

I haven’t figured out a solution or a workaround yet, except making every single callback in dashboard.py a function, as well as the callbacks of its own submodules, and run them within index.py, but that’s such a dirty solution and I’d rather find something more elegant.

Any help or info is very much appreciated.

you’re right, it’s dirty, but right now you do need to load all callbacks upfront. That’s because the page only asks for the list of callbacks once, on load, and we have no mechanism to update them later. Might be a nice piece to implement as part of the modularization idea we’ve been discussing in https://github.com/plotly/dash/issues/637

Ok got it, thanks for the quick reply.

There’s one thing which is still not clear to me tho, and it is the fact that if I visit localhost:8050/dashboard, callbacks are not loaded, but then if I refresh the page, then suddenly every callback works.

What’s the catch? In my head, if they didn’t get imported the first time, I don’t see why they would get imported fully the second.

When you import the module, those callbacks get added to the callback map on the server, but not sent to the browser. Then when you reload the page and the browser asks for the callbacks, it gets the bigger list including the new ones.

Right, got it, thanks for the reply