Permalink
Browse files

Implemented a separate application context.

  • Loading branch information...
1 parent a130597 commit 47288231fe8f9c6b2c413d50160c32c3884d5785 @mitsuhiko mitsuhiko committed Apr 9, 2012
Showing with 78 additions and 3 deletions.
  1. +16 −1 flask/app.py
  2. +53 −1 flask/ctx.py
  3. +9 −1 flask/globals.py
View
@@ -28,7 +28,7 @@
find_package
from .wrappers import Request, Response
from .config import ConfigAttribute, Config
-from .ctx import RequestContext
+from .ctx import RequestContext, AppContext
from .globals import _request_ctx_stack, request
from .sessions import SecureCookieSessionInterface
from .module import blueprint_is_module
@@ -1458,6 +1458,21 @@ def do_teardown_request(self):
return rv
request_tearing_down.send(self)
+ def app_context(self):
+ """Binds the application only. For as long as the application is bound
+ to the current context the :data:`flask.current_app` points to that
+ application. An application context is automatically created when a
+ request context is pushed if necessary.
+
+ Example usage::
+
+ with app.app_context():
+ ...
+
+ .. versionadded:: 0.9
+ """
+ return AppContext(self)
+
def request_context(self, environ):
"""Creates a :class:`~flask.ctx.RequestContext` from the given
environment and binds it to the current context. This must be used in
View
@@ -11,14 +11,22 @@
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
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 __init__(self, username, remote_addr=None):
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 @@ def __init__(self, app, environ):
# 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 @@ def push(self):
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 @@ def pop(self):
# 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
View
@@ -20,9 +20,17 @@ def _lookup_object(name):
return getattr(top, name)
+def _find_app():
+ top = _app_ctx_stack.top
+ if top is None:
+ raise RuntimeError('working outside of application context')
+ return top.app
+
+
# context locals
_request_ctx_stack = LocalStack()
-current_app = LocalProxy(partial(_lookup_object, 'app'))
+_app_ctx_stack = LocalStack()
+current_app = LocalProxy(_find_app)
request = LocalProxy(partial(_lookup_object, 'request'))
session = LocalProxy(partial(_lookup_object, 'session'))
g = LocalProxy(partial(_lookup_object, 'g'))

0 comments on commit 4728823

Please sign in to comment.