Issue with viewing pages when deployed with certain .py file names

Hi everyone,

I have noticed an issue when deploying my multipage Dash app where sometimes a page will not be registered despite it being set up correctly. However, if I merely change the name of the page’s python script file (to any other random name) it will then be registered and function normally.

This is a bit frustrating as I have many page scripts and would like to give them specific names to help organise them.

There are even instances where I can deploy the app locally on my PC and the pages are all register ok, but if I deploy them elsewhere (i.e. cPanel) some pages are not registered but by only changing their files names this is fixed.

Does anyone know what could be causing this issue?

Any help would be much appreciated.

Kind regards,
Jessica

this-page.py

#Relevant modules imported here
import dash 

#Register the page 
page_name = "this_page_name" 

dash.register_page(__name__, 
                   name = page_name, #Used by app.py
                   path="/the-path-for-this-page", #Unique for each page
                   order = 0
                   )

app.py

import dash
from dash import html

dash.register_page(__name__,
                   name = "App Name",
                   path="/the-path-for-this-app"
                   )

layout = html.Div(
    [
        dbc.Row([
            dbc.Col([
                dbc.Nav(
                    [
                    dbc.NavLink([
                        html.Div(page["name"], className = "ms-2"), 
                        ],
                        href = page["relative_path"], 
                        active = "exact",
                        #active = True,
                        )
                        for page in dash.page_registry.values()
                        if page["name"].startswith(("this_page_name")) #Only want specific pages to be displayed in the container
                        ], 
                    vertical = True, 
                    pills = True, 
                    className = "bg-light", 
                    )
                ])
            ]),
        ]
    )

With this example, the page will not be registered but if I only change the page file name from this-page.py to alternative-this-page.py, then it will work.

HI @jessieolough

If you are supplying your own name, then remove the __name__ as the first arg in dash.register_page

Hi @AnnMarieW,

Thanks for responding to my issue.

I’m afraid if I do that, I get the following error message when I try to run the app:
TypeError: register_page() missing 1 required positional argument: 'module'

Any other reasons why this issue could be caused?

Can you try it like this? Put the name in the first :

dash.register_page(
     page_name, #Used by app.py
     path="/the-path-for-this-page", #Unique for each page
     order = 0
)

Hi AnnMarieW,

Apologies for my delay in getting back. When I make the most recent changes you suggested, the script will run but the web screen shows the following error message:

NoLayoutException
dash.exceptions.NoLayoutException: No layout in module `page_name` in dash.page_registry

Traceback (most recent call last)
dash.exceptions.NoLayoutException: No layout in module `page_name` in dash.page_registry
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

To give more details about the overall problem: if I read the page registry from app.py, then all of the pages are present. However, if I read the page registry within a separate multipage app certain pages do not appear here and only changing their file name can make them appear here.

Many thanks,

Jess

Hi Jess,

Hard to see what’s going on with just the code snippets. Can you make a complete minimal example that replicates the error? Lots of example of minimal multi page apps here: GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page apps using Dash Pages

A simplified version of my code:

app.py (acting as a central log in page & directs to the user’s correct multipage report)

server = Flask(__name__)
app = dash.Dash(
    __name__, server=server, 
    use_pages=True, 
    suppress_callback_exceptions=True, 
    external_stylesheets = [dbc.themes.CERULEAN],
)


total_no_pages = 0
for page in dash.page_registry.values():
    print(page["module"])
    print(page["name"])
    print(page["path"])
    print(page["relative_path"])
    total_no_pages += 1
    print("---------")
    # print(page)
print("total_no_pages:", total_no_pages) #This will print all of the pages (correctly)

#data object is loaded in separately

VALID_USERNAME_PASSWORD = json.loads(data) 

# Updating the Flask Server configuration with Secret Key to encrypt the user session cookie
# server.config.update(SECRET_KEY=os.getenv("SECRET_KEY"))
server.config.update(SECRET_KEY="secret_key")

# Login manager object will be used to login / logout users
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = "/login"

class User(UserMixin):
    # User data model. It has to have at least self.id as a minimum
    def __init__(self, username):
        self.id = username

@login_manager.user_loader
def load_user(username):
    """This function loads the user by user id. Typically this looks up the user from a user database.
    We won't be registering or looking up users in this example, since we'll just login using LDAP server.
    So we'll simply return a User object with the passed in username.
    """
    return User(username)

app.layout = html.Div(
    [
     dbc.Container([
         dcc.Location(id="url"),
         html.Hr(),
         html.Div(id="user-status-header"),
         html.Hr(),
         dash.page_container,
         html.Br(),
         ]),
     ]
    )

@app.callback(
    Output("user-status-header", "children"),
    # Output("conditional-page-container", "children"),
    Input("url", "pathname"),
)
def update_authentication_status(_):
    if current_user.is_authenticated:
        # print(current_user.get_id())
        return dcc.Link("Logout", href="/logout")#, dash.page_container
    return dcc.Link("Login", href="/")


@app.callback(
    Output("output-state", "children"),
    Input("login-button", "n_clicks"),
    State("uname-box", "value"),
    State("pwd-box", "value"), 
    # prevent_initial_call=True
    )
def login_button_click(n_clicks, username, password):
    if n_clicks > 0:
        if VALID_USERNAME_PASSWORD.get(username) is None:
            return "Invalid username"
        if VALID_USERNAME_PASSWORD.get(username) == password:
            login_user(User(username))
            print(current_user.get_id())
            if current_user.get_id() == "correct_username":
                children = ["Login Successful ", dcc.Link("View Reports", href="/link_to_multipage_report")]
            else:
                children = "Incorrect Username or Password"

            return children
        children = "Incorrect Username or Password"
        return children
    
if __name__ == "__main__":
    app.run(debug=True)

Within the multipage report.py the user is directed to:

import dash
from dash import html, dcc
import dash_bootstrap_components as dbc


dash.register_page(__name__,
                   name = "Report Page",
                   path="/link_to_multipage_report"
                   )

total_no_pages = 0
for page in dash.page_registry.values():
    print(page["module"])
    print(page["name"])
    print(page["path"])
    print(page["relative_path"])
    total_no_pages += 1
    print("---------")
    # print(page)
print("total_no_pages:", total_no_pages) #When this is printed, certain pages (previously present in the app.py page_registry) are not present

layout = html.Div(
    [
        dbc.Row([
            dbc.Col([
                dbc.Nav(
                    [
                    dbc.NavLink([
                        html.Div(page["name"], className = "ms-2"), 
                        ],
                        href = page["relative_path"], 
                        active = "exact",
                        #active = True,
                        )
                        for page in dash.page_registry.values()
                        if page["name"].startswith(("relevant_query"))
                        ], 
                    vertical = True, 
                    pills = True, 
                    className = "bg-light", 
                    )
                ])
            ]),
        html.Hr(),
        ]
    )

Any idea why between the app.py and the directed multipage report.py somes pages go missing?

Many thanks,
Jess

you are defining the name twice - once with __name__ as the first param then again with name = "Report Page"

Hi AnnMarieW,

Thanks for getting back to me. To avoid conflict between __name__ and name, I’ve removed name so that it looks like this:

dash.register_page(__name__,
                   path = "/link_to_multipage_report"
                   )

And I’ve also updated the app.py script to that it is looking for pages with a certain module name (__name__) , but this is not working.

Other pages with the same format as I previously described will load and function perfectly well. I find that the issue is sporadic and unpredictable when one page will suddenly no longer be detected within report.py but can be detected in app.py.

Are there any other potential reasons for this problem?

@jessieolough
It would be easier to help if you had a complete minimal example that I could run. Perhaps you could put an example in GitHub?

Note that the dash.page_registry is built as the dash.register_page function is called. If you are trying to access the page_registry from within a file in the pages folder, the page_registry may not be built yet. You can get around that by using a function as described in the Dash Page Registry section of the docs:

If you would like to run an example clone this repo and run the example #7 multi_page_layout_functions