mirror of https://github.com/pallets/flask.git
Implemented a separate application context.
This commit is contained in:
parent
a1305973bf
commit
47288231fe
17
flask/app.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
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
|
||||
|
|
|
|||
|
|
@ -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…
Reference in New Issue