diff --git a/CHANGES b/CHANGES index f37dfc54..f0cb9723 100644 --- a/CHANGES +++ b/CHANGES @@ -80,6 +80,8 @@ Major release, unreleased exception inheritance hierarchies. Register handlers explicitly for each exception if you don't want to traverse the MRO. (`#2362`_) - Fix incorrect JSON encoding of aware, non-UTC datetimes. (`#2374`_) +- Template auto reloading will honor the ``run`` command's ``debug`` flag even + if ``app.jinja_env`` was already accessed. (`#2373`_) .. _#1489: https://github.com/pallets/flask/pull/1489 .. _#1621: https://github.com/pallets/flask/pull/1621 @@ -104,6 +106,7 @@ Major release, unreleased .. _#2358: https://github.com/pallets/flask/pull/2358 .. _#2362: https://github.com/pallets/flask/pull/2362 .. _#2374: https://github.com/pallets/flask/pull/2374 +.. _#2373: https://github.com/pallets/flask/pull/2373 Version 0.12.2 -------------- diff --git a/flask/app.py b/flask/app.py index ece1e2bf..04c39547 100644 --- a/flask/app.py +++ b/flask/app.py @@ -703,6 +703,28 @@ class Flask(_PackageBoundObject): """ return open(os.path.join(self.instance_path, resource), mode) + def _get_templates_auto_reload(self): + """Reload templates when they are changed. Used by + :meth:`create_jinja_environment`. + + This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If + not set, it will be enabled in debug mode. + + .. versionadded:: 1.0 + This property was added but the underlying config and behavior + already existed. + """ + rv = self.config['TEMPLATES_AUTO_RELOAD'] + return rv if rv is not None else self.debug + + def _set_templates_auto_reload(self, value): + self.config['TEMPLATES_AUTO_RELOAD'] = value + + templates_auto_reload = property( + _get_templates_auto_reload, _set_templates_auto_reload + ) + del _get_templates_auto_reload, _set_templates_auto_reload + def create_jinja_environment(self): """Creates the Jinja2 environment based on :attr:`jinja_options` and :meth:`select_jinja_autoescape`. Since 0.7 this also adds @@ -715,13 +737,13 @@ class Flask(_PackageBoundObject): ``TEMPLATES_AUTO_RELOAD`` configuration option. """ options = dict(self.jinja_options) + if 'autoescape' not in options: options['autoescape'] = self.select_jinja_autoescape + if 'auto_reload' not in options: - if self.config['TEMPLATES_AUTO_RELOAD'] is not None: - options['auto_reload'] = self.config['TEMPLATES_AUTO_RELOAD'] - else: - options['auto_reload'] = self.debug + options['auto_reload'] = self.templates_auto_reload + rv = self.jinja_environment(self, **options) rv.globals.update( url_for=url_for, @@ -806,6 +828,22 @@ class Flask(_PackageBoundObject): rv.update(processor()) return rv + def _reconfigure_for_run_debug(self, debug): + """The ``run`` commands will set the application's debug flag. Some + application configuration may already be calculated based on the + previous debug value. This method will recalculate affected values. + + Called by the :func:`flask.cli.run` command or :meth:`Flask.run` + method if the debug flag is set explicitly in the call. + + :param debug: the new value of the debug flag + + .. versionadded:: 1.0 + Reconfigures ``app.jinja_env.auto_reload``. + """ + self.debug = debug + self.jinja_env.auto_reload = self.templates_auto_reload + def run(self, host=None, port=None, debug=None, **options): """Runs the application on a local development server. @@ -859,19 +897,24 @@ class Flask(_PackageBoundObject): explain_ignored_app_run() return - from werkzeug.serving import run_simple + if debug is not None: + self._reconfigure_for_run_debug(bool(debug)) + _host = '127.0.0.1' _port = 5000 server_name = self.config.get("SERVER_NAME") sn_host, sn_port = None, None + if server_name: sn_host, _, sn_port = server_name.partition(':') + host = host or sn_host or _host port = int(port or sn_port or _port) - if debug is not None: - self.debug = bool(debug) options.setdefault('use_reloader', self.debug) options.setdefault('use_debugger', self.debug) + + from werkzeug.serving import run_simple + try: run_simple(host, port, self, **options) finally: diff --git a/flask/cli.py b/flask/cli.py index 0982aa1c..4b5323c7 100644 --- a/flask/cli.py +++ b/flask/cli.py @@ -319,8 +319,10 @@ class ScriptInfo(object): be returned. """ __traceback_hide__ = True + if self._loaded_app is not None: return self._loaded_app + if self.create_app is not None: rv = call_factory(self.create_app, self) else: @@ -330,10 +332,14 @@ class ScriptInfo(object): 'the FLASK_APP environment variable.\n\nFor more ' 'information see ' 'http://flask.pocoo.org/docs/latest/quickstart/') + rv = locate_app(self, self.app_import_path) + debug = get_debug_flag() + if debug is not None: - rv.debug = debug + rv._reconfigure_for_run_debug(debug) + self._loaded_app = rv return rv diff --git a/tests/test_templating.py b/tests/test_templating.py index 2763dfbd..aaec54d7 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -14,6 +14,7 @@ import pytest import flask import logging from jinja2 import TemplateNotFound +import werkzeug.serving def test_context_processing(app, client): @@ -385,6 +386,20 @@ def test_templates_auto_reload(app): app.config['TEMPLATES_AUTO_RELOAD'] = True assert app.jinja_env.auto_reload is True +def test_templates_auto_reload_debug_run(app, monkeypatch): + def run_simple_mock(*args, **kwargs): + pass + + monkeypatch.setattr(werkzeug.serving, 'run_simple', run_simple_mock) + + app.run() + assert app.templates_auto_reload == False + assert app.jinja_env.auto_reload == False + + app.run(debug=True) + assert app.templates_auto_reload == True + assert app.jinja_env.auto_reload == True + def test_template_loader_debugging(test_apps): from blueprintapp import app