Flask: Jinja templates do not auto reload if Flask app debug enabled solely via app.run(debug=True)

Created on 12 Jun 2016  路  15Comments  路  Source: pallets/flask

When enabling debug mode via app.run(debug=True), code changes result in an auto-reload but Jinja templates are cached until the app is manually is restarted.

At https://github.com/pallets/flask/blob/21d595bee73e65a28201709bd1a8b97c42aff5d2/flask/app.py#L695 Flask checks if the config["TEMPLATE_AUTO_RELOAD"] is explicitly set. If not, Jinja's options["auto_reload"] is set to app.debug.

However, if you instantiate your Flask object _then_ call app.run(debug=True) without loading a config, template auto reloading is not enabled (app.debug was False when the Flask app was instantiated).

At https://github.com/pallets/flask/blob/21d595bee73e65a28201709bd1a8b97c42aff5d2/flask/app.py#L839 we enable reloading code and enable the debugger. My proposed fix would be to also enable template reloading (jinja_env.auto_reload = self.debug) here.

This would result is less confusion ("Debug is enabled but my templates don't auto reload") and make the template reloading behaviour consistent with the code reloading behaviour ("If no config is set or debug is not explicitly set in config, and the site calls app.run(debug=True), then enable the relevant auto reloading features").

Most helpful comment

For me it worked with the following code:

if __name__ == '__main__':
    app.jinja_env.auto_reload = True
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.run(debug=True, host='0.0.0.0')

All 15 comments

Your proposed fix makes sense to me.

Some further clarification...

In attempting to put together a simple proof of concept for the issue, I've further narrowed down exactly where it's triggered.

In a very simple PoC, if I ...

  1. Instantiate my Flask app
  2. Add some routes
  3. Call app.run(debug=True)

... the issue does not manifest. I can alter templates and they are reloaded as expected.

This works because the jinja_env isn't actually initialised until _after_ app.run(debug=True) is called (so it's seeing app.debug == True).

However, if I ...

  1. Instantiate my Flask app
  2. Add some routes
  3. Access my app.jinja_env object (thereby initialising the Jinja2 environment)
  4. Call app.run(debug=True)

... template auto-reloading doesn't work as expected.

This is because accessing app.jinja_env creates the Jinja environment, reading app.debug before app.run(debug=True) sets it to True.

I think the issue still stands despite the narrower impact of only affecting users who access the jinja_env.

In my case, I'm adding Jinja2 global before calling app.run(debug=True) which has the unexpected side effect of disabling template auto-reloading and never re-enabling it when I'm running under debug mode.

It seems like a simple change, so if there are no objections I'd like to try to fix this and create a PR for it.

I've created a PR (#1910) resolving this. Test suite passes and it resolves the issue for the particular use case outlined above (reading jinja_env before calling app.run(debug=True)).

I think I'm running into the same issue, if I configure custom jinja filters via @app.template_filter('format_date'). This stops auto-template reloading.

If I explicitly say app.config['TEMPLATES_AUTO_RELOAD'] = True before that, reloading works again.

Is this still an issue? auto reload doesn't seem to work at all
@patricksurry doing app.config explicitly doesn't do anything for me... was wondering why this would be

Even a simple hello world app doesn't want to reload

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def hello():
    return "hello world"

if __name__ == "__main__":
    app.config['TEMPLATES_AUTO_RELOAD']=True
    app.run(debug=True,use_reloader=True)

To those out there who may be facing the same problem using a factory pattern.

Maybe the following post has something to do with you.

https://blog.socratic.org/the-one-weird-trick-that-cut-our-flask-page-load-time-by-70-87145335f679#.biy44wahq

When I removed the following line of code from my factory pattern, I was able to just refresh the browser and the changes from the html appeared. It seems the template changes did take affect after you reload. However the flask app in terminal did not say anything about detection on the html file. Maybe we can add some sort of detection on there to let developers know what file was changed.

app.jinja_env.cache = {}

Hope this helps out some people.

Cheers!

For me it worked with the following code:

if __name__ == '__main__':
    app.jinja_env.auto_reload = True
    app.config['TEMPLATES_AUTO_RELOAD'] = True
    app.run(debug=True, host='0.0.0.0')

I can confirm that adding the line
~python
app.jinja_env.auto_reload = True
~

as suggested by @silgon corrects the behaviour in my situation. Without setting auto_reload on the jinja_env to True manually, auto reloading will not work for templates.

For completeness sake, the code I use for running the server (current_app is setup using click and the group feature)
~~~python
@click.command(name="serve", short_help="run the application server")
@click.option("-h", "--host", default="127.0.0.1", type=str)
@click.option("-p", "--port", default=5000, type=int)
@click.option("-d", "--debug", is_flag=True)
@click.option("-r", "--reload", is_flag=True)
def cli(host, port, debug, reload):
if reload:
current_app.jinja_env.auto_reload = True
current_app.config["TEMPLATES_AUTO_RELOAD"] = True

current_app.run(
    host=host, port=port,
    debug=debug, use_debugger=debug,
    use_reloader=reload,
)

~~~

@davidism is it intentional that the template reload behaviour is linked to the debug flag? Wouldn't it make more sense to tie it to the reload command instead? I mean, isn't using debug functionality something different than autoreload? Please correct me if I am wrong.

True, linking it to the reloader makes more sense...

The behavior was never previously linked to the reloader. The reloader is a different mechanism than the Jinja cache. I'm good with this as-is, and taking the reloader into account would complicate things.

Thank you for the clarification. It is just that looking at the terminology here, it seems a bit odd that debug does add debugging functionality and reloading :-)

@davidism I can, by the way, confirm that the merged changes are working as intended over here.

If found that when using:

@app.template_filter()
def foo(bar):
    pass

Somewhere in my main code.
I still need:

if __name__ == '__main__':
    app.jinja_env.auto_reload = True
    app.run(debug=True, host='0.0.0.0')

To make template reloading on page refresh work. I didn't need app.config['TEMPLATES_AUTO_RELOAD'] = True.

Just to add here, since this thread helped me, the app.jinja_env.auto_reload = True made it work for me again.

To summarize for posterity: if you touch the Jinja2 environment in any way before the app.run call (e.g. adding a filter), you will need the line above before app.run for your templates to be auto-reloaded after changes. This is at least what I've observed.

Thanks to folks here on the resolution, saved me some trouble. 馃樅

Was this page helpful?
0 / 5 - 0 ratings