forked from orbit-oss/flask
flask.g is now on the app context and not the request context
This commit is contained in:
parent
61d43c7f12
commit
1949c4a9ab
9 changed files with 71 additions and 20 deletions
5
CHANGES
5
CHANGES
|
|
@ -34,6 +34,11 @@ Release date to be decided.
|
||||||
in less bytes being transmitted over the network. It's disabled by
|
in less bytes being transmitted over the network. It's disabled by
|
||||||
default to not cause confusion with existing libraries that might expect
|
default to not cause confusion with existing libraries that might expect
|
||||||
``flask.json.dumps`` to return bytestrings by default.
|
``flask.json.dumps`` to return bytestrings by default.
|
||||||
|
- ``flask.g`` is now stored on the app context instead of the request
|
||||||
|
context.
|
||||||
|
- ``flask.Flask.request_globals_class`` got renamed to
|
||||||
|
``flask.Flask.app_ctx_globals_class`` which is a better name to what it
|
||||||
|
does since 0.10.
|
||||||
|
|
||||||
Version 0.9
|
Version 0.9
|
||||||
-----------
|
-----------
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,10 @@ thing, like it does for :class:`request` and :class:`session`.
|
||||||
Just store on this whatever you want. For example a database
|
Just store on this whatever you want. For example a database
|
||||||
connection or the user that is currently logged in.
|
connection or the user that is currently logged in.
|
||||||
|
|
||||||
|
Starting with Flask 0.10 this is stored on the application context and
|
||||||
|
no longer on the request context which means it becomes available if
|
||||||
|
only the application context is bound and not yet a request.
|
||||||
|
|
||||||
This is a proxy. See :ref:`notes-on-proxies` for more information.
|
This is a proxy. See :ref:`notes-on-proxies` for more information.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,13 @@ extensions for tuples and strings with HTML markup.
|
||||||
In order to not break people's sessions it is possible to continue using
|
In order to not break people's sessions it is possible to continue using
|
||||||
the old session system by using the `Flask-OldSessions_` extension.
|
the old session system by using the `Flask-OldSessions_` extension.
|
||||||
|
|
||||||
|
Flask also started storing the :data:`flask.g` object on the application
|
||||||
|
context instead of the request context. This change should be transparent
|
||||||
|
for you but it means that you now can store things on the ``g`` object
|
||||||
|
when there is no request context yet but an application context. The old
|
||||||
|
``flask.Flask.request_globals_class`` attribute was renamed to
|
||||||
|
:attr:`flask.Flask.app_ctx_globals_class`.
|
||||||
|
|
||||||
.. _Flask-OldSessions: http://packages.python.org/Flask-OldSessions/
|
.. _Flask-OldSessions: http://packages.python.org/Flask-OldSessions/
|
||||||
|
|
||||||
Version 0.9
|
Version 0.9
|
||||||
|
|
|
||||||
22
flask/app.py
22
flask/app.py
|
|
@ -28,7 +28,7 @@ from .helpers import _PackageBoundObject, url_for, get_flashed_messages, \
|
||||||
from . import json
|
from . import json
|
||||||
from .wrappers import Request, Response
|
from .wrappers import Request, Response
|
||||||
from .config import ConfigAttribute, Config
|
from .config import ConfigAttribute, Config
|
||||||
from .ctx import RequestContext, AppContext, _RequestGlobals
|
from .ctx import RequestContext, AppContext, _AppCtxGlobals
|
||||||
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
|
||||||
|
|
@ -157,8 +157,24 @@ class Flask(_PackageBoundObject):
|
||||||
#: 3. Return None instead of AttributeError on expected attributes.
|
#: 3. Return None instead of AttributeError on expected attributes.
|
||||||
#: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
|
#: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
|
||||||
#:
|
#:
|
||||||
#: .. versionadded:: 0.9
|
#: In Flask 0.9 this property was called `request_globals_class` but it
|
||||||
request_globals_class = _RequestGlobals
|
#: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
|
||||||
|
#: flask.g object is not application context scoped.
|
||||||
|
#:
|
||||||
|
#: .. versionadded:: 0.10
|
||||||
|
app_ctx_globals_class = _AppCtxGlobals
|
||||||
|
|
||||||
|
# Backwards compatibility support
|
||||||
|
def _get_request_globals_class(self):
|
||||||
|
return self.app_ctx_globals_class
|
||||||
|
def _set_request_globals_class(self, value):
|
||||||
|
from warnings import warn
|
||||||
|
warn(DeprecationWarning('request_globals_class attribute is now '
|
||||||
|
'called app_ctx_globals_class'))
|
||||||
|
self.app_ctx_globals_class = value
|
||||||
|
request_globals_class = property(_get_request_globals_class,
|
||||||
|
_set_request_globals_class)
|
||||||
|
del _get_request_globals_class, _set_request_globals_class
|
||||||
|
|
||||||
#: The debug flag. Set this to `True` to enable debugging of the
|
#: The debug flag. Set this to `True` to enable debugging of the
|
||||||
#: application. In debug mode the debugger will kick in when an unhandled
|
#: application. In debug mode the debugger will kick in when an unhandled
|
||||||
|
|
|
||||||
11
flask/ctx.py
11
flask/ctx.py
|
|
@ -17,7 +17,7 @@ from .globals import _request_ctx_stack, _app_ctx_stack
|
||||||
from .module import blueprint_is_module
|
from .module import blueprint_is_module
|
||||||
|
|
||||||
|
|
||||||
class _RequestGlobals(object):
|
class _AppCtxGlobals(object):
|
||||||
"""A plain object."""
|
"""A plain object."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -101,6 +101,7 @@ class AppContext(object):
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.url_adapter = app.create_url_adapter(None)
|
self.url_adapter = app.create_url_adapter(None)
|
||||||
|
self.g = app.app_ctx_globals_class()
|
||||||
|
|
||||||
# Like request context, app contexts can be pushed multiple times
|
# Like request context, app contexts can be pushed multiple times
|
||||||
# but there a basic "refcount" is enough to track them.
|
# but there a basic "refcount" is enough to track them.
|
||||||
|
|
@ -164,7 +165,6 @@ class RequestContext(object):
|
||||||
self.app = app
|
self.app = app
|
||||||
self.request = app.request_class(environ)
|
self.request = app.request_class(environ)
|
||||||
self.url_adapter = app.create_url_adapter(self.request)
|
self.url_adapter = app.create_url_adapter(self.request)
|
||||||
self.g = app.request_globals_class()
|
|
||||||
self.flashes = None
|
self.flashes = None
|
||||||
self.session = None
|
self.session = None
|
||||||
|
|
||||||
|
|
@ -195,6 +195,13 @@ class RequestContext(object):
|
||||||
if bp is not None and blueprint_is_module(bp):
|
if bp is not None and blueprint_is_module(bp):
|
||||||
self.request._is_old_module = True
|
self.request._is_old_module = True
|
||||||
|
|
||||||
|
def _get_g(self):
|
||||||
|
return _app_ctx_stack.top.g
|
||||||
|
def _set_g(self, value):
|
||||||
|
_app_ctx_stack.top.g = value
|
||||||
|
g = property(_get_g, _set_g)
|
||||||
|
del _get_g, _set_g
|
||||||
|
|
||||||
def match_request(self):
|
def match_request(self):
|
||||||
"""Can be overridden by a subclass to hook into the matching
|
"""Can be overridden by a subclass to hook into the matching
|
||||||
of the request.
|
of the request.
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,21 @@
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from werkzeug.local import LocalStack, LocalProxy
|
from werkzeug.local import LocalStack, LocalProxy
|
||||||
|
|
||||||
def _lookup_object(name):
|
|
||||||
|
def _lookup_req_object(name):
|
||||||
top = _request_ctx_stack.top
|
top = _request_ctx_stack.top
|
||||||
if top is None:
|
if top is None:
|
||||||
raise RuntimeError('working outside of request context')
|
raise RuntimeError('working outside of request context')
|
||||||
return getattr(top, name)
|
return getattr(top, name)
|
||||||
|
|
||||||
|
|
||||||
|
def _lookup_app_object(name):
|
||||||
|
top = _app_ctx_stack.top
|
||||||
|
if top is None:
|
||||||
|
raise RuntimeError('working outside of application context')
|
||||||
|
return getattr(top, name)
|
||||||
|
|
||||||
|
|
||||||
def _find_app():
|
def _find_app():
|
||||||
top = _app_ctx_stack.top
|
top = _app_ctx_stack.top
|
||||||
if top is None:
|
if top is None:
|
||||||
|
|
@ -31,6 +39,6 @@ def _find_app():
|
||||||
_request_ctx_stack = LocalStack()
|
_request_ctx_stack = LocalStack()
|
||||||
_app_ctx_stack = LocalStack()
|
_app_ctx_stack = LocalStack()
|
||||||
current_app = LocalProxy(_find_app)
|
current_app = LocalProxy(_find_app)
|
||||||
request = LocalProxy(partial(_lookup_object, 'request'))
|
request = LocalProxy(partial(_lookup_req_object, 'request'))
|
||||||
session = LocalProxy(partial(_lookup_object, 'session'))
|
session = LocalProxy(partial(_lookup_req_object, 'session'))
|
||||||
g = LocalProxy(partial(_lookup_object, 'g'))
|
g = LocalProxy(partial(_lookup_app_object, 'g'))
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,14 @@ def _default_template_ctx_processor():
|
||||||
`session` and `g`.
|
`session` and `g`.
|
||||||
"""
|
"""
|
||||||
reqctx = _request_ctx_stack.top
|
reqctx = _request_ctx_stack.top
|
||||||
if reqctx is None:
|
appctx = _app_ctx_stack.top
|
||||||
return {}
|
rv = {}
|
||||||
return dict(
|
if appctx is not None:
|
||||||
request=reqctx.request,
|
rv['g'] = appctx.g
|
||||||
session=reqctx.session,
|
if reqctx is not None:
|
||||||
g=reqctx.g
|
rv['request'] = reqctx.request
|
||||||
)
|
rv['session'] = reqctx.session
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
class Environment(BaseEnvironment):
|
class Environment(BaseEnvironment):
|
||||||
|
|
|
||||||
|
|
@ -65,13 +65,13 @@ class AppContextTestCase(FlaskTestCase):
|
||||||
|
|
||||||
self.assert_equal(cleanup_stuff, [None])
|
self.assert_equal(cleanup_stuff, [None])
|
||||||
|
|
||||||
def test_custom_request_globals_class(self):
|
def test_custom_app_ctx_globals_class(self):
|
||||||
class CustomRequestGlobals(object):
|
class CustomRequestGlobals(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.spam = 'eggs'
|
self.spam = 'eggs'
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
app.request_globals_class = CustomRequestGlobals
|
app.app_ctx_globals_class = CustomRequestGlobals
|
||||||
with app.test_request_context():
|
with app.app_context():
|
||||||
self.assert_equal(
|
self.assert_equal(
|
||||||
flask.render_template_string('{{ g.spam }}'), 'eggs')
|
flask.render_template_string('{{ g.spam }}'), 'eggs')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1104,8 +1104,11 @@ class BasicFunctionalityTestCase(FlaskTestCase):
|
||||||
c.get('/fail')
|
c.get('/fail')
|
||||||
|
|
||||||
self.assert_(flask._request_ctx_stack.top is not None)
|
self.assert_(flask._request_ctx_stack.top is not None)
|
||||||
flask._request_ctx_stack.pop()
|
self.assert_(flask._app_ctx_stack.top is not None)
|
||||||
|
# implicit appctx disappears too
|
||||||
|
flask._request_ctx_stack.top.pop()
|
||||||
self.assert_(flask._request_ctx_stack.top is None)
|
self.assert_(flask._request_ctx_stack.top is None)
|
||||||
|
self.assert_(flask._app_ctx_stack.top is None)
|
||||||
|
|
||||||
|
|
||||||
class ContextTestCase(FlaskTestCase):
|
class ContextTestCase(FlaskTestCase):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue