Armin Ronacher committed 1949c4a

flask.g is now on the app context and not the request context

  • Participants
  • Parent commits 61d43c7

Comments (0)

Files changed (9)

   in less bytes being transmitted over the network.  It's disabled by
   default to not cause confusion with existing libraries that might expect
   ``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

File docs/api.rst

    Just store on this whatever you want.  For example a database
    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.

File docs/upgrading.rst

 In order to not break people's sessions it is possible to continue using
 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
 .. _Flask-OldSessions:
 Version 0.9

File flask/

 from . import json
 from .wrappers import Request, Response
 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 .sessions import SecureCookieSessionInterface
 from .module import blueprint_is_module
     #: 3. Return None instead of AttributeError on expected attributes.
     #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
-    #: .. versionadded:: 0.9
-    request_globals_class = _RequestGlobals
+    #: In Flask 0.9 this property was called `request_globals_class` but it
+    #: 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
     #: application.  In debug mode the debugger will kick in when an unhandled

File flask/

 from .module import blueprint_is_module
-class _RequestGlobals(object):
+class _AppCtxGlobals(object):
     """A plain object."""
     def __init__(self, app): = app
         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
         # but there a basic "refcount" is enough to track them. = app
         self.request = app.request_class(environ)
         self.url_adapter = app.create_url_adapter(self.request)
-        self.g = app.request_globals_class()
         self.flashes = None
         self.session = None
             if bp is not None and blueprint_is_module(bp):
                 self.request._is_old_module = True
+    def _get_g(self):
+        return
+    def _set_g(self, value):
+ = value
+    g = property(_get_g, _set_g)
+    del _get_g, _set_g
     def match_request(self):
         """Can be overridden by a subclass to hook into the matching
         of the request.

File flask/

 from functools import partial
 from werkzeug.local import LocalStack, LocalProxy
-def _lookup_object(name):
+def _lookup_req_object(name):
     top =
     if top is None:
         raise RuntimeError('working outside of request context')
     return getattr(top, name)
+def _lookup_app_object(name):
+    top =
+    if top is None:
+        raise RuntimeError('working outside of application context')
+    return getattr(top, name)
 def _find_app():
     top =
     if top is None:
 _request_ctx_stack = LocalStack()
 _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'))
+request = LocalProxy(partial(_lookup_req_object, 'request'))
+session = LocalProxy(partial(_lookup_req_object, 'session'))
+g = LocalProxy(partial(_lookup_app_object, 'g'))

File flask/

     `session` and `g`.
     reqctx =
-    if reqctx is None:
-        return {}
-    return dict(
-        request=reqctx.request,
-        session=reqctx.session,
-        g=reqctx.g
-    )
+    appctx =
+    rv = {}
+    if appctx is not None:
+        rv['g'] = appctx.g
+    if reqctx is not None:
+        rv['request'] = reqctx.request
+        rv['session'] = reqctx.session
+    return rv
 class Environment(BaseEnvironment):

File flask/testsuite/

         self.assert_equal(cleanup_stuff, [None])
-    def test_custom_request_globals_class(self):
+    def test_custom_app_ctx_globals_class(self):
         class CustomRequestGlobals(object):
             def __init__(self):
                 self.spam = 'eggs'
         app = flask.Flask(__name__)
-        app.request_globals_class = CustomRequestGlobals
-        with app.test_request_context():
+        app.app_ctx_globals_class = CustomRequestGlobals
+        with app.app_context():
                 flask.render_template_string('{{ g.spam }}'), 'eggs')

File flask/testsuite/

         self.assert_( is not None)
-        flask._request_ctx_stack.pop()
+        self.assert_( is not None)
+        # implicit appctx disappears too
         self.assert_( is None)
+        self.assert_( is None)
 class ContextTestCase(FlaskTestCase):