2021-01-29

How does Flask appear to be skipping print statements

I have a Dash application that lets the user filter a pandas dataframe, which results in a graph. They can also download a CSV of the filtered dataframe. This is accomplished by passing arguments to the URL, retrieving the arguments using flask.request.args, refiltering the database, and writing the output to a file.

While working on this solution, I added print statements to help me track variable values. Although the download link is working with the desired result, I came across some behavior that I don't fully understand. I think this may have something to do with @app.server.route and when/how it is executed.

For example:

  1. Print statements are not always executed. They are executed sometimes.
  2. They seem to have a higher rate of execution once I apply filters, rather than clicking the download link with no filters applied.
  3. After applying a filter, clicking the download link, and confirming that it caused the print statements to execute, reloading the app and applying the same filter may result in the print statements not executing.

The download link always performs as intended, but I do not understand how the dataframe is being filtered and written via @app.server.route('/download_csv'), while also skipping over the print statements.

UPDATE

I have produced an MRE for Jupyter notebooks. Please note that you must pip install jupyter-dash for this code to execute.

Some notes:

  1. I ran three tests where I would click the download CSV link 10x each.
  2. In the first two tests, the print statements executed 8/10 times.
  3. In the final test, they executed 3/10 times.
  4. In the third test, I cleared the age dropdown and performed most of the tests with it as 'Null.' Sometimes print statements will execute and return 'Null', however most times there was no execution.

The MRE is below:

Update 2

After waiting 24hrs and running the code again, all of the lines in @app.server.route seem to be executing. That is, until I click the download button quickly after changing filters. When this happens, I can get the print statements to not execute. Despite not executing, the other lines are. Some guesses as to what is going on:

  1. When the print statements don't execute, it seems that a previous version of the code is being executed. Perhaps it is stored in some temporary memory location?
  2. It seems that restarting the system or long periods of inactivity cause the current version of the code to become the default when print statements don't execute.
  3. print statements seem to execute less frequently after quick filter changes and download requests.
import plotly.express as px
from jupyter_dash import JupyterDash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import numpy as np
# Load Data
df = pd.DataFrame({'id':np.arange(100), 'name':['cat', 'dog', 'mouse', 'bird', 'rabbit']*20, 'age':np.random.randint(1,30,size=100)})
# Build App
app = JupyterDash(__name__)
app.layout = html.Div([
    html.H1("JupyterDash Demo"),
    dcc.Graph(id='graph'),
    html.Label([
        "names",
        dcc.Dropdown(
            id='names', clearable=False,
            value='cat', options=[
                {'label': names, 'value': names}
                for names in df.name.unique()
            ])
    ]),
    
        html.Label([
        "age",
        dcc.Dropdown(
            id='age', clearable=True,
             options=[
                {'label': att, 'value': att}
                for att in df.age.unique()
            ])
    ]),
    html.Br(),
    html.A(
        "Download CSV",
        id="download_csv",
        href="#",
        className="btn btn-outline-secondary btn-sm"
    )
])
# Define callback to update graph
@app.callback(
    [Output('graph', 'figure'),
    Output('download_csv', 'href')],
    [Input("names", "value"),
     Input('age', 'value')]
)
def update_figure(names, age):
    
    if not names:
        names = 'Null'
        fil_df = df
    else: 
        fil_df = df[df['name'].isin([names])]
        fig = px.bar(
            fil_df, x='id', y='age',
            title="Animals"
        )
    
    if not age:
        age = 'Null'
        fil_df = fil_df
    else:
        fil_df =  fil_df[(fil_df['age'].isin([age]))]
        fig = px.bar(
        fil_df, x='id', y='age', title="Animals"
        )
        
        
    return fig, "/download_csv?value={}/{}".format(names, age)
   



    
app.run_server(mode='inline')

@app.server.route('/download_csv')
def download_csv():
    value = flask.request.args.get('value')
    value = value.split('/')
    
    selected_1 = value[0]
    selected_2 = value[1]
    
    print(selected_1)
    print(selected_2)
    
    str_io = io.StringIO()
    df.to_csv(str_io)

    mem = io.BytesIO()
    mem.write(str_io.getvalue().encode('utf-8'))
    mem.seek(0)
    str_io.close()
    return flask.send_file(mem,
                           mimetype='text/csv',
                           attachment_filename='downloadFile.csv',
                           as_attachment=True)


from Recent Questions - Stack Overflow https://ift.tt/3t8XA4K
https://ift.tt/eA8V8J

No comments:

Post a Comment