Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] debug=True and @app.server.before_requestAttributeError: '_AppCtxGlobals' object has no attribute 'timing_information' #1475

Closed
anders-kiaer opened this issue Dec 1, 2020 · 6 comments
Labels
bug something broken

Comments

@anders-kiaer
Copy link
Contributor

Describe your context
Please provide us your environment so we can easily reproduce the issue.

  • replace the result of pip list | grep dash below
dash                                  1.17.0
dash-core-components                  1.13.0
dash-html-components                  1.1.1
dash-renderer                         1.8.3
dash-table                            4.11.0

Describe the bug

With debug=True:

Traceback (most recent call last):
  File "[...]/python3.7/site-packages/flask/app.py", line 2464, in __call__
    return self.wsgi_app(environ, start_response)
  File "[...]/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
    response = self.handle_exception(e)
  File "[...]/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "[...]/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "[...]/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "[...]/python3.7/site-packages/flask/app.py", line 1953, in full_dispatch_request
    return self.finalize_request(rv)
  File "[...]/python3.7/site-packages/flask/app.py", line 1970, in finalize_request
    response = self.process_response(response)
  File "[...]/python3.7/site-packages/flask/app.py", line 2267, in process_response
    response = handler(response)
  File "[...]/python3.7/site-packages/dash/dash.py", line 1469, in _after_request
    dash_total = flask.g.timing_information["__dash_server"]
  File "[...]/python3.7/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'timing_information'

What happens

In our use case we use the Dash provided Flask server (app.server) to set up a before_request. On certain conditions (more specifically, certain GET parameters in the URL) we do a flask redirect.

In dash<1.16 the minimal example below works, however in dash>=1.16 it fails with the above traceback.

A minimal example

import flask
import dash
import dash_html_components as html


app = dash.Dash()

app.layout = html.Div("Hello world")

@app.server.before_request
def some_function():
    if flask.request.args.get("redirect_me") == "yes":
        return flask.redirect(flask.request.base_url)
                
if __name__ == "__main__":
    app.run_server(debug=True)

Go to http://127.0.0.1:8050/?redirect_me=yes

Expected behaviour

Not entirely sure what is best behavior. One possible option: If server timing is not possible to calculate, return response without adding header "Server-Timing" and displaying it in the frontend (for the given request)?

dash/dash/dash.py

Lines 1468 to 1483 in ab212a3

def _after_request(response):
dash_total = flask.g.timing_information["__dash_server"]
dash_total["dur"] = round((time.time() - dash_total["dur"]) * 1000)
for name, info in flask.g.timing_information.items():
value = name
if info.get("desc") is not None:
value += ';desc="{}"'.format(info["desc"])
if info.get("dur") is not None:
value += ";dur={}".format(info["dur"])
response.headers.add("Server-Timing", value)
return response

@alexcjohnson
Copy link
Collaborator

Ah interesting - so when you do a redirect in your own before_request, the before_request handler we use to initialize timing info is never executed, but our after_request handler is? Or perhaps the redirect clears flask.g?

Whichever it is, I think it'd be fine to just bail out of our after_request if there's no timing_information in flask.g. In general we only care about these headers for callbacks so it wouldn't matter in your case at all, but even if there were some variant of this in which callbacks lose their timing header that's not a big deal.

@alexcjohnson alexcjohnson added the bug something broken label Dec 2, 2020
@tophers42
Copy link

Running into this issue. Any recommendations for workarounds?

@TillerBurr
Copy link
Contributor

From my understanding, the cause is that the custom before_request is causing the Dash _before_request function in

dash/dash/dash.py

Lines 1463 to 1466 in ab212a3

def _before_request():
flask.g.timing_information = {
"__dash_server": {"dur": time.time(), "desc": None}
}
to not be executed.

What I did as a workaround was to create a new before_request with the same function that only exists if my app is in debug. I use a DEBUG value in my Flask config to denote which mode it should be in. It really shouldn't matter if you check for the mode beforehand, since I would guess that the new before_request doesn't add much to response time. This is a modified version of the above example that works for me:

import flask
import dash
import dash_html_components as html
import time


app = dash.Dash()
app.server.config["DEBUG"] = True
app.layout = html.Div("Hello world")

if app.server.config["DEBUG"]:
    @app.server.before_request
    def _before_request():
        flask.g.timing_information = {
            "__dash_server": {"dur": time.time(), "desc": None}
        }


@app.server.before_request
def some_function():
    if flask.request.args.get("redirect_me") == "yes":
        return flask.redirect(flask.request.base_url)


if __name__ == "__main__":
    app.run_server(debug=app.server.config.get("DEBUG", False))

@tophers42
Copy link

Thanks @baurt

@anders-kiaer anders-kiaer changed the title [BUG] debug=True and flask redirect → AttributeError: '_AppCtxGlobals' object has no attribute 'timing_information' [BUG] debug=True and @app.server.before_requestAttributeError: '_AppCtxGlobals' object has no attribute 'timing_information' May 6, 2021
@remibaar
Copy link
Contributor

remibaar commented May 21, 2021

Issue is resolved in PR #1640
PR is merged, thus this issue can be closed

@anders-kiaer
Copy link
Contributor Author

@remibaar 🎉 👏 - thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

No branches or pull requests

5 participants