Browse Source

Merge pull request #2580 from pallets/session-attrs

improve documentation for session attributes
pull/2581/head
David Lord 7 years ago committed by GitHub
parent
commit
26f413e1e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 63
      flask/sessions.py
  2. 11
      tests/test_basic.py

63
flask/sessions.py

@ -10,6 +10,7 @@
"""
import hashlib
import warnings
from collections import MutableMapping
from datetime import datetime
from itsdangerous import BadSignature, URLSafeTimedSerializer
@ -19,43 +20,55 @@ from flask.helpers import is_ip, total_seconds
from flask.json.tag import TaggedJSONSerializer
class SessionMixin(object):
"""Expands a basic dictionary with an accessors that are expected
by Flask extensions and users for the session.
"""
class SessionMixin(MutableMapping):
"""Expands a basic dictionary with session attributes."""
def _get_permanent(self):
@property
def permanent(self):
"""This reflects the ``'_permanent'`` key in the dict."""
return self.get('_permanent', False)
def _set_permanent(self, value):
@permanent.setter
def permanent(self, value):
self['_permanent'] = bool(value)
#: this reflects the ``'_permanent'`` key in the dict.
permanent = property(_get_permanent, _set_permanent)
del _get_permanent, _set_permanent
#: some session backends can tell you if a session is new, but that is
#: not necessarily guaranteed. Use with caution. The default mixin
#: implementation just hardcodes ``False`` in.
#: Some implementations can detect whether a session is newly
#: created, but that is not guaranteed. Use with caution. The mixin
# default is hard-coded ``False``.
new = False
#: for some backends this will always be ``True``, but some backends will
#: default this to false and detect changes in the dictionary for as
#: long as changes do not happen on mutable structures in the session.
#: The default mixin implementation just hardcodes ``True`` in.
#: Some implementations can detect changes to the session and set
#: this when that happens. The mixin default is hard coded to
#: ``True``.
modified = True
#: the accessed variable indicates whether or not the session object has
#: been accessed in that request. This allows flask to append a `Vary:
#: Cookie` header to the response if the session is being accessed. This
#: allows caching proxy servers, like Varnish, to use both the URL and the
#: session cookie as keys when caching pages, preventing multiple users
#: from being served the same cache.
#: Some implementations can detect when session data is read or
#: written and set this when that happens. The mixin default is hard
#: coded to ``True``.
accessed = True
class SecureCookieSession(CallbackDict, SessionMixin):
"""Base class for sessions based on signed cookies."""
"""Base class for sessions based on signed cookies.
This session backend will set the :attr:`modified` and
:attr:`accessed` attributes. It cannot reliably track whether a
session is new (vs. empty), so :attr:`new` remains hard coded to
``False``.
"""
#: When data is changed, this is set to ``True``. Only the session
#: dictionary itself is tracked; if the session contains mutable
#: data (for example a nested dict) then this must be set to
#: ``True`` manually when modifying that data. The session cookie
#: will only be written to the response if this is ``True``.
modified = False
#: When data is read or written, this is set to ``True``. Used by
# :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
#: header, which allows caching proxies to cache different pages for
#: different users.
accessed = False
def __init__(self, initial=None):
def on_update(self):
@ -63,8 +76,6 @@ class SecureCookieSession(CallbackDict, SessionMixin):
self.accessed = True
super(SecureCookieSession, self).__init__(initial, on_update)
self.modified = False
self.accessed = False
def __getitem__(self, key):
self.accessed = True

11
tests/test_basic.py

@ -221,12 +221,21 @@ def test_endpoint_decorator(app, client):
def test_session(app, client):
@app.route('/set', methods=['POST'])
def set():
assert not flask.session.accessed
assert not flask.session.modified
flask.session['value'] = flask.request.form['value']
assert flask.session.accessed
assert flask.session.modified
return 'value set'
@app.route('/get')
def get():
return flask.session['value']
assert not flask.session.accessed
assert not flask.session.modified
v = flask.session.get('value', 'None')
assert flask.session.accessed
assert not flask.session.modified
return v
assert client.post('/set', data={'value': '42'}).data == b'value set'
assert client.get('/get').data == b'42'

Loading…
Cancel
Save