Implemented a separate application context.

This commit is contained in:
Armin Ronacher 2012-04-09 14:34:12 +01:00
parent a1305973bf
commit 47288231fe
3 changed files with 78 additions and 3 deletions

View file

@ -11,7 +11,7 @@
from werkzeug.exceptions import HTTPException
from .globals import _request_ctx_stack
from .globals import _request_ctx_stack, _app_ctx_stack
from .module import blueprint_is_module
@ -19,6 +19,14 @@ class _RequestGlobals(object):
pass
def _push_app_if_necessary(app):
top = _app_ctx_stack.top
if top is None or top.app != app:
ctx = app.app_context()
ctx.push()
return ctx
def has_request_context():
"""If you have code that wants to test if a request context is there or
not this function can be used. For instance, you may want to take advantage
@ -51,6 +59,36 @@ def has_request_context():
return _request_ctx_stack.top is not None
class AppContext(object):
"""The application context binds an application object implicitly
to the current thread or greenlet, similar to how the
:class:`RequestContext` binds request information. The application
context is also implicitly created if a request context is created
but the application is not on top of the individual application
context.
"""
def __init__(self, app):
self.app = app
def push(self):
"""Binds the app context to the current context."""
_app_ctx_stack.push(self)
def pop(self):
"""Pops the app context."""
rv = _app_ctx_stack.pop()
assert rv is self, 'Popped wrong app context. (%r instead of %r)' \
% (rv, self)
def __enter__(self):
self.push()
return self
def __exit__(self, exc_type, exc_value, tb):
self.pop()
class RequestContext(object):
"""The request context contains all request relevant information. It is
created at the beginning of the request and pushed to the
@ -93,6 +131,11 @@ class RequestContext(object):
# is pushed the preserved context is popped.
self.preserved = False
# Indicates if pushing this request context also triggered the pushing
# of an application context. If it implicitly pushed an application
# context, it will be stored there
self._pushed_application_context = None
self.match_request()
# XXX: Support for deprecated functionality. This is going away with
@ -130,6 +173,10 @@ class RequestContext(object):
if top is not None and top.preserved:
top.pop()
# Before we push the request context we have to ensure that there
# is an application context.
self._pushed_application_context = _push_app_if_necessary(self.app)
_request_ctx_stack.push(self)
# Open the session at the moment that the request context is
@ -154,6 +201,11 @@ class RequestContext(object):
# so that we don't require the GC to be active.
rv.request.environ['werkzeug.request'] = None
# Get rid of the app as well if necessary.
if self._pushed_application_context:
self._pushed_application_context.pop()
self._pushed_application_context = None
def __enter__(self):
self.push()
return self