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 find_package
from .wrappers import Request, Response from .wrappers import Request, Response
from .config import ConfigAttribute, Config from .config import ConfigAttribute, Config
from .ctx import RequestContext from .ctx import RequestContext, AppContext
from .globals import _request_ctx_stack, request from .globals import _request_ctx_stack, request
from .sessions import SecureCookieSessionInterface from .sessions import SecureCookieSessionInterface
from .module import blueprint_is_module from .module import blueprint_is_module
@ -1458,6 +1458,21 @@ class Flask(_PackageBoundObject):
return rv return rv
request_tearing_down.send(self) 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): def request_context(self, environ):
"""Creates a :class:`~flask.ctx.RequestContext` from the given """Creates a :class:`~flask.ctx.RequestContext` from the given
environment and binds it to the current context. This must be used in 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 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 from .module import blueprint_is_module
@ -19,6 +19,14 @@ class _RequestGlobals(object):
pass 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(): def has_request_context():
"""If you have code that wants to test if a request context is there or """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 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 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): class RequestContext(object):
"""The request context contains all request relevant information. It is """The request context contains all request relevant information. It is
created at the beginning of the request and pushed to the 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. # is pushed the preserved context is popped.
self.preserved = False 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() self.match_request()
# XXX: Support for deprecated functionality. This is going away with # 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: if top is not None and top.preserved:
top.pop() 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) _request_ctx_stack.push(self)
# Open the session at the moment that the request context is # 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. # so that we don't require the GC to be active.
rv.request.environ['werkzeug.request'] = None 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): def __enter__(self):
self.push() self.push()
return self return self

10
flask/globals.py

@ -20,9 +20,17 @@ def _lookup_object(name):
return getattr(top, 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 # context locals
_request_ctx_stack = LocalStack() _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')) request = LocalProxy(partial(_lookup_object, 'request'))
session = LocalProxy(partial(_lookup_object, 'session')) session = LocalProxy(partial(_lookup_object, 'session'))
g = LocalProxy(partial(_lookup_object, 'g')) g = LocalProxy(partial(_lookup_object, 'g'))

Loading…
Cancel
Save