Skip to content

Commit 1949c4a

Browse files
committed
flask.g is now on the app context and not the request context
1 parent 61d43c7 commit 1949c4a

File tree

9 files changed

+71
-20
lines changed

9 files changed

+71
-20
lines changed

CHANGES

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ Release date to be decided.
3434
in less bytes being transmitted over the network. It's disabled by
3535
default to not cause confusion with existing libraries that might expect
3636
``flask.json.dumps`` to return bytestrings by default.
37+
- ``flask.g`` is now stored on the app context instead of the request
38+
context.
39+
- ``flask.Flask.request_globals_class`` got renamed to
40+
``flask.Flask.app_ctx_globals_class`` which is a better name to what it
41+
does since 0.10.
3742

3843
Version 0.9
3944
-----------

docs/api.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ thing, like it does for :class:`request` and :class:`session`.
258258
Just store on this whatever you want. For example a database
259259
connection or the user that is currently logged in.
260260

261+
Starting with Flask 0.10 this is stored on the application context and
262+
no longer on the request context which means it becomes available if
263+
only the application context is bound and not yet a request.
264+
261265
This is a proxy. See :ref:`notes-on-proxies` for more information.
262266

263267

docs/upgrading.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ extensions for tuples and strings with HTML markup.
3636
In order to not break people's sessions it is possible to continue using
3737
the old session system by using the `Flask-OldSessions_` extension.
3838

39+
Flask also started storing the :data:`flask.g` object on the application
40+
context instead of the request context. This change should be transparent
41+
for you but it means that you now can store things on the ``g`` object
42+
when there is no request context yet but an application context. The old
43+
``flask.Flask.request_globals_class`` attribute was renamed to
44+
:attr:`flask.Flask.app_ctx_globals_class`.
45+
3946
.. _Flask-OldSessions: http://packages.python.org/Flask-OldSessions/
4047

4148
Version 0.9

flask/app.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from . import json
2929
from .wrappers import Request, Response
3030
from .config import ConfigAttribute, Config
31-
from .ctx import RequestContext, AppContext, _RequestGlobals
31+
from .ctx import RequestContext, AppContext, _AppCtxGlobals
3232
from .globals import _request_ctx_stack, request
3333
from .sessions import SecureCookieSessionInterface
3434
from .module import blueprint_is_module
@@ -157,8 +157,24 @@ class Flask(_PackageBoundObject):
157157
#: 3. Return None instead of AttributeError on expected attributes.
158158
#: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
159159
#:
160-
#: .. versionadded:: 0.9
161-
request_globals_class = _RequestGlobals
160+
#: In Flask 0.9 this property was called `request_globals_class` but it
161+
#: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
162+
#: flask.g object is not application context scoped.
163+
#:
164+
#: .. versionadded:: 0.10
165+
app_ctx_globals_class = _AppCtxGlobals
166+
167+
# Backwards compatibility support
168+
def _get_request_globals_class(self):
169+
return self.app_ctx_globals_class
170+
def _set_request_globals_class(self, value):
171+
from warnings import warn
172+
warn(DeprecationWarning('request_globals_class attribute is now '
173+
'called app_ctx_globals_class'))
174+
self.app_ctx_globals_class = value
175+
request_globals_class = property(_get_request_globals_class,
176+
_set_request_globals_class)
177+
del _get_request_globals_class, _set_request_globals_class
162178

163179
#: The debug flag. Set this to `True` to enable debugging of the
164180
#: application. In debug mode the debugger will kick in when an unhandled

flask/ctx.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from .module import blueprint_is_module
1818

1919

20-
class _RequestGlobals(object):
20+
class _AppCtxGlobals(object):
2121
"""A plain object."""
2222
pass
2323

@@ -101,6 +101,7 @@ class AppContext(object):
101101
def __init__(self, app):
102102
self.app = app
103103
self.url_adapter = app.create_url_adapter(None)
104+
self.g = app.app_ctx_globals_class()
104105

105106
# Like request context, app contexts can be pushed multiple times
106107
# but there a basic "refcount" is enough to track them.
@@ -164,7 +165,6 @@ def __init__(self, app, environ):
164165
self.app = app
165166
self.request = app.request_class(environ)
166167
self.url_adapter = app.create_url_adapter(self.request)
167-
self.g = app.request_globals_class()
168168
self.flashes = None
169169
self.session = None
170170

@@ -195,6 +195,13 @@ def __init__(self, app, environ):
195195
if bp is not None and blueprint_is_module(bp):
196196
self.request._is_old_module = True
197197

198+
def _get_g(self):
199+
return _app_ctx_stack.top.g
200+
def _set_g(self, value):
201+
_app_ctx_stack.top.g = value
202+
g = property(_get_g, _set_g)
203+
del _get_g, _set_g
204+
198205
def match_request(self):
199206
"""Can be overridden by a subclass to hook into the matching
200207
of the request.

flask/globals.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,21 @@
1313
from functools import partial
1414
from werkzeug.local import LocalStack, LocalProxy
1515

16-
def _lookup_object(name):
16+
17+
def _lookup_req_object(name):
1718
top = _request_ctx_stack.top
1819
if top is None:
1920
raise RuntimeError('working outside of request context')
2021
return getattr(top, name)
2122

2223

24+
def _lookup_app_object(name):
25+
top = _app_ctx_stack.top
26+
if top is None:
27+
raise RuntimeError('working outside of application context')
28+
return getattr(top, name)
29+
30+
2331
def _find_app():
2432
top = _app_ctx_stack.top
2533
if top is None:
@@ -31,6 +39,6 @@ def _find_app():
3139
_request_ctx_stack = LocalStack()
3240
_app_ctx_stack = LocalStack()
3341
current_app = LocalProxy(_find_app)
34-
request = LocalProxy(partial(_lookup_object, 'request'))
35-
session = LocalProxy(partial(_lookup_object, 'session'))
36-
g = LocalProxy(partial(_lookup_object, 'g'))
42+
request = LocalProxy(partial(_lookup_req_object, 'request'))
43+
session = LocalProxy(partial(_lookup_req_object, 'session'))
44+
g = LocalProxy(partial(_lookup_app_object, 'g'))

flask/templating.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ def _default_template_ctx_processor():
2222
`session` and `g`.
2323
"""
2424
reqctx = _request_ctx_stack.top
25-
if reqctx is None:
26-
return {}
27-
return dict(
28-
request=reqctx.request,
29-
session=reqctx.session,
30-
g=reqctx.g
31-
)
25+
appctx = _app_ctx_stack.top
26+
rv = {}
27+
if appctx is not None:
28+
rv['g'] = appctx.g
29+
if reqctx is not None:
30+
rv['request'] = reqctx.request
31+
rv['session'] = reqctx.session
32+
return rv
3233

3334

3435
class Environment(BaseEnvironment):

flask/testsuite/appctx.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ def cleanup(exception):
6565

6666
self.assert_equal(cleanup_stuff, [None])
6767

68-
def test_custom_request_globals_class(self):
68+
def test_custom_app_ctx_globals_class(self):
6969
class CustomRequestGlobals(object):
7070
def __init__(self):
7171
self.spam = 'eggs'
7272
app = flask.Flask(__name__)
73-
app.request_globals_class = CustomRequestGlobals
74-
with app.test_request_context():
73+
app.app_ctx_globals_class = CustomRequestGlobals
74+
with app.app_context():
7575
self.assert_equal(
7676
flask.render_template_string('{{ g.spam }}'), 'eggs')
7777

flask/testsuite/basic.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,8 +1104,11 @@ def fail_func():
11041104
c.get('/fail')
11051105

11061106
self.assert_(flask._request_ctx_stack.top is not None)
1107-
flask._request_ctx_stack.pop()
1107+
self.assert_(flask._app_ctx_stack.top is not None)
1108+
# implicit appctx disappears too
1109+
flask._request_ctx_stack.top.pop()
11081110
self.assert_(flask._request_ctx_stack.top is None)
1111+
self.assert_(flask._app_ctx_stack.top is None)
11091112

11101113

11111114
class ContextTestCase(FlaskTestCase):

0 commit comments

Comments
 (0)