Browse Source

Implemented a separate application context.

pull/483/head
Armin Ronacher 13 years ago
parent
commit
47288231fe
  1. 17
      flask/app.py
  2. 54
      flask/ctx.py
  3. 10
      flask/globals.py

17
flask/app.py

@ -28,7 +28,7 @@ from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
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 @@ class Flask(_PackageBoundObject):
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

54
flask/ctx.py

@ -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

10
flask/globals.py

@ -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'))

Loading…
Cancel
Save