Permalink
Browse files

deprecated init_jinja_globals

  • Loading branch information...
1 parent 4c8c503 commit 0da56d7f5cfb6a637129444bfe0d6bf2584363ac @mitsuhiko mitsuhiko committed Mar 18, 2011
Showing with 88 additions and 16 deletions.
  1. +3 −0 CHANGES
  2. +34 −16 flask/app.py
  3. +31 −0 flask/helpers.py
  4. +20 −0 tests/flask_tests.py
View
@@ -40,6 +40,9 @@ Release date to be announced, codename to be selected
- Added `teardown_request` decorator, for functions that should run at the end
of a request regardless of whether an exception occurred.
- Implemented :func:`flask.has_request_context`
+- Deprecated `init_jinja_globals`. Override the
+ :meth:`~flask.Flask.create_jinja_environment` method instead to
+ achieve the same functionality.
Version 0.6.1
-------------
View
@@ -24,7 +24,7 @@
MethodNotAllowed
from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
- _tojson_filter, _endpoint_from_view_func
+ locked_cached_property, _tojson_filter, _endpoint_from_view_func
from .wrappers import Request, Response
from .config import ConfigAttribute, Config
from .ctx import _RequestContext
@@ -317,11 +317,6 @@ def __init__(self, import_name, static_path=None):
endpoint='static',
view_func=self.send_static_file)
- #: The Jinja2 environment. It is created from the
- #: :attr:`jinja_options`.
- self.jinja_env = self.create_jinja_environment()
- self.init_jinja_globals()
-
@property
def propagate_exceptions(self):
"""Returns the value of the `PROPAGATE_EXCEPTIONS` configuration
@@ -356,16 +351,43 @@ def logger(self):
self._logger = rv = create_logger(self)
return rv
+ @locked_cached_property
+ def jinja_env(self):
+ """The Jinja2 environment used to load templates."""
+ rv = self.create_jinja_environment()
+
+ # Hack to support the init_jinja_globals method which is supported
+ # until 1.0 but has an API deficiency.
+ if getattr(self.init_jinja_globals, 'im_func', None) is not \
+ Flask.init_jinja_globals.im_func:
+ from warnings import warn
+ warn(DeprecationWarning('This flask class uses a customized '
+ 'init_jinja_globals() method which is deprecated. '
+ 'Move the code from that method into the '
+ 'create_jinja_environment() method instead.'))
+ self.__dict__['jinja_env'] = rv
+ self.init_jinja_globals()
+
+ return rv
+
def create_jinja_environment(self):
"""Creates the Jinja2 environment based on :attr:`jinja_options`
- and :meth:`select_jinja_autoescape`.
+ and :meth:`select_jinja_autoescape`. Since 0.7 this also adds
+ the Jinja2 globals and filters after initialization. Override
+ this function to customize the behavior.
.. versionadded:: 0.5
"""
options = dict(self.jinja_options)
if 'autoescape' not in options:
options['autoescape'] = self.select_jinja_autoescape
- return Environment(loader=self.create_jinja_loader(), **options)
+ rv = Environment(loader=self.create_jinja_loader(), **options)
+ rv.globals.update(
+ url_for=url_for,
+ get_flashed_messages=get_flashed_messages
+ )
+ rv.filters['tojson'] = _tojson_filter
+ return rv
def create_jinja_loader(self):
"""Creates the loader for the Jinja2 environment. Can be used to
@@ -376,17 +398,13 @@ def create_jinja_loader(self):
return _DispatchingJinjaLoader(self)
def init_jinja_globals(self):
- """Called directly after the environment was created to inject
- some defaults (like `url_for`, `get_flashed_messages` and the
- `tojson` filter.
+ """Deprecated. Used to initialize the Jinja2 globals.
.. versionadded:: 0.5
+ .. versionchanged:: 0.7
+ This method is deprecated with 0.7. Override
+ :meth:`create_jinja_environment` instead.
"""
- self.jinja_env.globals.update(
- url_for=url_for,
- get_flashed_messages=get_flashed_messages
- )
- self.jinja_env.filters['tojson'] = _tojson_filter
def select_jinja_autoescape(self, filename):
"""Returns `True` if autoescaping should be active for the given
View
@@ -15,6 +15,7 @@
import mimetypes
from time import time
from zlib import adler32
+from threading import RLock
# try to load the best simplejson implementation available. If JSON
# is not installed, we add a failing class.
@@ -58,6 +59,10 @@ def _tojson_filter(*args, **kwargs):
_tojson_filter = json.dumps
+# sentinel
+_missing = object()
+
+
# what separators does this operating system provide that are not a slash?
# this is used by the send_from_directory function to ensure that nobody is
# able to access files from outside the filesystem.
@@ -435,6 +440,32 @@ def _get_package_path(name):
return os.getcwd()
+class locked_cached_property(object):
+ """A decorator that converts a function into a lazy property. The
+ function wrapped is called the first time to retrieve the result
+ and then that calculated result is used the next time you access
+ the value. Works like the one in Werkzeug but has a lock for
+ thread safety.
+ """
+
+ def __init__(self, func, name=None, doc=None):
+ self.__name__ = name or func.__name__
+ self.__module__ = func.__module__
+ self.__doc__ = doc or func.__doc__
+ self.func = func
+ self.lock = RLock()
+
+ def __get__(self, obj, type=None):
+ if obj is None:
+ return self
+ with self.lock:
+ value = obj.__dict__.get(self.__name__, _missing)
+ if value is _missing:
+ value = self.func(obj)
+ obj.__dict__[self.__name__] = value
+ return value
+
+
class _PackageBoundObject(object):
def __init__(self, import_name):
View
@@ -1564,6 +1564,25 @@ def record(sender, exception):
flask.got_request_exception.disconnect(record, app)
+class DeprecationsTestCase(unittest.TestCase):
+
+ def test_init_jinja_globals(self):
+ class MyFlask(flask.Flask):
+ def init_jinja_globals(self):
+ self.jinja_env.globals['foo'] = '42'
+
+ with catch_warnings() as log:
+ app = MyFlask(__name__)
+ @app.route('/')
+ def foo():
+ return app.jinja_env.globals['foo']
+
+ c = app.test_client()
+ assert c.get('/').data == '42'
+ assert len(log) == 1
+ assert 'init_jinja_globals' in str(log[0]['message'])
+
+
def suite():
from minitwit_tests import MiniTwitTestCase
from flaskr_tests import FlaskrTestCase
@@ -1576,6 +1595,7 @@ def suite():
suite.addTest(unittest.makeSuite(LoggingTestCase))
suite.addTest(unittest.makeSuite(ConfigTestCase))
suite.addTest(unittest.makeSuite(SubdomainTestCase))
+ suite.addTest(unittest.makeSuite(DeprecationsTestCase))
if flask.json_available:
suite.addTest(unittest.makeSuite(JSONTestCase))
if flask.signals_available:

0 comments on commit 0da56d7

Please sign in to comment.