Error when adding new page to the multipage app

I have a multipage app that has the following structure:

App.py
	pages(folder)
		Home.py
		Dashboard.py

The app works well with no issue, now I have created a new page that I tested independently and works well as well, however when I add the new page to the group, the App.py fails. Here is the new structure"

App.py
	pages(folder)
		Home.py
		Dashboard.py
		Reports.py

The error message I receive is:

Traceback (most recent call last):
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\pkgutil.py", line 496, in find_loader
    spec = importlib.util.find_spec(fullname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib.util>", line 94, in find_spec
ModuleNotFoundError: No module named 'pages.C:'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\App\App.py", line 8, in <module>
    app = dash.Dash(__name__, use_pages=True)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\dash\dash.py", line 504, in __init__
    self.init_app()
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\dash\dash.py", line 588, in init_app
    self.enable_pages()
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\dash\dash.py", line 2041, in enable_pages
    self._import_layouts_from_pages()
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\dash\dash.py", line 2012, in _import_layouts_from_pages
    spec.loader.exec_module(page_module)
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "C:\App\pages\Reports.py", line 11, in <module>
    app = dash.Dash(__name__, title='Network Monitoring Dashboard', external_stylesheets=[dbc.themes.BOOTSTRAP],
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\dash\dash.py", line 382, in __init__
    self.server = flask.Flask(name) if server else None
                  ^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\flask\app.py", line 566, in __init__
    super().__init__(
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\flask\scaffold.py", line 112, in __init__
    root_path = get_root_path(self.import_name)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\site-packages\flask\helpers.py", line 611, in get_root_path
    loader = pkgutil.get_loader(import_name)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\pkgutil.py", line 482, in get_loader
    return find_loader(fullname)
           ^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\xxx\anaconda3\envs\dashboard\Lib\pkgutil.py", line 502, in find_loader
    raise ImportError(msg.format(fullname, type(ex), ex)) from ex
ImportError: Error while finding loader for 'pages.C:.App.pages.Reports' (<class 'ModuleNotFoundError'>: No module named 'pages.C:')

If I remove the Dashboard.py file, the newly added page works, its only when all are present, I tried renaming all to make sure that there is no name conflict with no luck, below are the codes for the files"

App.py

import dash
from dash import html, dcc, callback, Input, Output, Dash
import os, time

app = dash.Dash(__name__, use_pages=True)
app.layout = html.Div(
    [
        dcc.Store(id="store", data={}),
        html.Div("Network Traffic Dashboard", style={'fontSize':50, 'textAlign':'center'}),
        html.Div([
            dcc.Link(page['name']+"  |  ", href=page['path'])
            for page in dash.page_registry.values()
        ]),
        html.Hr(),
        html.Div(id='selected_nic'),
        dash.page_container
    ]
)

print(dash.page_registry.values())
layout = app.layout

@app.callback(
    Output('selected_nic', 'nic'),
    [Input('store', 'data')]
)
def capturing_loop(nic):
    while nic != None:
	Some operations not to worry about

if __name__ == "__main__":
    if not os.path.exists(r'c:/DataCapture'):
        os.mkdir(r'c:\DataCapture')
    app.run_server(debug=True)

Home.py

import dash
from dash import dcc, html, Input, Output, State, callback, Dash
import pandas as pd
import subprocess, io

dash.register_page(__name__, path='/')

layout = html.Div([
    html.H1(children='Welcome to the Network Traffic Monitoring Dashboard', style={
            'text-align': 'center'}),
    html.Div([
        html.Label(['Please select a graph to start capturing Traffic, then move to page 2:'], style={
                   'font-weight': 'bold'}),
        dcc.RadioItems(
            id='nic_selection',
            options=df[2],
            persistence=False,
            inline=False),
        html.Button(id='submit_btn', n_clicks=0, children='Start'),
        html.Button(id='stop_btn', n_clicks=0, children='Stop'),
    ])])

@callback(
    Output('store', 'data'),
    [State('nic_selection', 'value')],
    [Input('submit_btn', 'n_clicks')]
)
def update_output(value, n_clicks):
    print('Value is', value)
    if n_clicks is None:
        raise PreventUpdate
    store = value
    return store

Dashboard.py

import dash
from dash import dcc, html, callback, Input, Output, Dash
import plotly.express as px
import pandas as pd
import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import os, glob

dash.register_page(__name__)

app = dash.Dash(__name__, title='Network Monitoring Dashboard', external_stylesheets=[dbc.themes.BOOTSTRAP],
                suppress_callback_exceptions=True)

layout = html.Div([
    dcc.Interval(
        id='interval_component',
        interval=5 * 3000,
        n_intervals=0
    ),
    dbc.Col([
        html.Div([
            html.Label(['Choose a graph:'], style={'font-weight': 'bold'}),
            dcc.Dropdown(
                id='dropdown',
                options=[
                ],
                multi=True,
                value=['fig1'],
                style={"width": "60%"},
                clearable=False
            ),
        ]),
        html.Div(id='graph_container'),
    ])
])

@callback(Output('graph_container', 'children'),
          [Input('dropdown', 'value'),
           Input('interval_component', 'n_intervals'),
           Input('store', 'data')])
def update_graph(value, n, nic):
    path = r'C:/DataCapture/'
    files_path = os.path.join(path, '*')
#	there are functions here also

And here is the final file, Reports.py:

import dash
from dash import dcc, html, Input, Output, State, callback, Dash
import plotly.express as px
import pandas as pd
#import plotly.graph_objects as go
import dash_bootstrap_components as dbc
import os, glob

dash.register_page(__name__)

app = dash.Dash(__name__, title='Network Monitoring Dashboard', external_stylesheets=[dbc.themes.BOOTSTRAP],
                suppress_callback_exceptions=True)
layout = html.Div([
    html.H1('You can enter your filters here', className='text-center fs-1 text-primary'),
    html.Button(id='submit_btn', n_clicks=0, children='Submit'),
    html.Div(id='graph_container'),
])

# layout = app.layout
@callback(
    Output('graph_container', 'children'),
    [State('src_IP', 'value'),
    State('dst_IP', 'value'),
    State('prt', 'value'),
    Input('submit_btn', 'n_clicks')]
)
def Select_options(value1, value2, value3, n_click):
    path = r'C:/DataCapture/'
    files_path = os.path.join(path, '*')

# if __name__ == "__main__":
#     app.run_server(debug=True)

Thanks in advance

1 Like

Hi @arafeek
The app should only be defined in app.py. Try taking this out of each of the apps in the pages folder:

app = dash.Dash(__name__, title='Network Monitoring Dashboard', external_stylesheets=[dbc.themes.BOOTSTRAP],
                suppress_callback_exceptions=True)

Yes, it works, thanks

On a side note, how do you set the sequence of the pages to be displayed, currently it is alphabetically, but just because I set the last page as reports, but I actually want to make customreport, which would make it before dashboard, and this is something I don’t want to have

Thanks again

Hi, there is an order option when registering the page

Order: The order of the pages in page_registry. If not supplied, then the filename is used and the page with path / has order 0

2 Likes

HI @arafeek

You might find this repo helpful - it has examples of lots of Pages features, including the order prop that @jcuypers recommended.

3 Likes