summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2012-10-27 21:32:50 +0200
committerAymeric Augustin <aymeric.augustin@m4x.org>2012-10-28 09:20:54 +0100
commit845d8408e7aa09a63c98f160b2c6bc9fa6dbb20f (patch)
tree75654d9552cb46094a57cb8ac726c24b2beba62c
parentc5da577b9e394b3b4696e4f4ca495c82951b6678 (diff)
[1.5.x] Added optional kwargs to get_expiry_age/date.
This change allows for cleaner tests: we can test the exact output. Refs #18194: this change makes it possible to compute session expiry dates at times other than when the session is saved. Fixed #18458: the existence of the `modification` kwarg implies that you must pass it to get_expiry_age/date if you call these functions outside of a short request - response cycle (the intended use case). Backport of cd17a24 from master.
-rw-r--r--django/contrib/sessions/backends/base.py40
-rw-r--r--django/contrib/sessions/backends/cached_db.py2
-rw-r--r--django/contrib/sessions/tests.py46
-rw-r--r--docs/topics/http/sessions.txt11
4 files changed, 73 insertions, 26 deletions
diff --git a/django/contrib/sessions/backends/base.py b/django/contrib/sessions/backends/base.py
index 65bbe059eb..1f63c3b45a 100644
--- a/django/contrib/sessions/backends/base.py
+++ b/django/contrib/sessions/backends/base.py
@@ -170,28 +170,52 @@ class SessionBase(object):
_session = property(_get_session)
- def get_expiry_age(self, expiry=None):
+ def get_expiry_age(self, **kwargs):
"""Get the number of seconds until the session expires.
- expiry is an optional parameter specifying the datetime of expiry.
+ Optionally, this function accepts `modification` and `expiry` keyword
+ arguments specifying the modification and expiry of the session.
"""
- if expiry is None:
+ try:
+ modification = kwargs['modification']
+ except KeyError:
+ modification = timezone.now()
+ # Make the difference between "expiry=None passed in kwargs" and
+ # "expiry not passed in kwargs", in order to guarantee not to trigger
+ # self.load() when expiry is provided.
+ try:
+ expiry = kwargs['expiry']
+ except KeyError:
expiry = self.get('_session_expiry')
+
if not expiry: # Checks both None and 0 cases
return settings.SESSION_COOKIE_AGE
if not isinstance(expiry, datetime):
return expiry
- delta = expiry - timezone.now()
+ delta = expiry - modification
return delta.days * 86400 + delta.seconds
- def get_expiry_date(self):
- """Get session the expiry date (as a datetime object)."""
- expiry = self.get('_session_expiry')
+ def get_expiry_date(self, **kwargs):
+ """Get session the expiry date (as a datetime object).
+
+ Optionally, this function accepts `modification` and `expiry` keyword
+ arguments specifying the modification and expiry of the session.
+ """
+ try:
+ modification = kwargs['modification']
+ except KeyError:
+ modification = timezone.now()
+ # Same comment as in get_expiry_age
+ try:
+ expiry = kwargs['expiry']
+ except KeyError:
+ expiry = self.get('_session_expiry')
+
if isinstance(expiry, datetime):
return expiry
if not expiry: # Checks both None and 0 cases
expiry = settings.SESSION_COOKIE_AGE
- return timezone.now() + timedelta(seconds=expiry)
+ return modification + timedelta(seconds=expiry)
def set_expiry(self, value):
"""
diff --git a/django/contrib/sessions/backends/cached_db.py b/django/contrib/sessions/backends/cached_db.py
index 8e4cf8b7e7..31c6fbfce3 100644
--- a/django/contrib/sessions/backends/cached_db.py
+++ b/django/contrib/sessions/backends/cached_db.py
@@ -40,7 +40,7 @@ class SessionStore(DBStore):
)
data = self.decode(s.session_data)
cache.set(self.cache_key, data,
- self.get_expiry_age(s.expire_date))
+ self.get_expiry_age(expiry=s.expire_date))
except (Session.DoesNotExist, SuspiciousOperation):
self.create()
data = {}
diff --git a/django/contrib/sessions/tests.py b/django/contrib/sessions/tests.py
index 527e8eb331..44c3b485e9 100644
--- a/django/contrib/sessions/tests.py
+++ b/django/contrib/sessions/tests.py
@@ -197,31 +197,43 @@ class SessionTestsMixin(object):
self.assertEqual(self.session.get_expiry_age(), settings.SESSION_COOKIE_AGE)
def test_custom_expiry_seconds(self):
- # Using seconds
+ modification = timezone.now()
+
self.session.set_expiry(10)
- delta = self.session.get_expiry_date() - timezone.now()
- self.assertIn(delta.seconds, (9, 10))
- age = self.session.get_expiry_age()
- self.assertIn(age, (9, 10))
+ date = self.session.get_expiry_date(modification=modification)
+ self.assertEqual(date, modification + timedelta(seconds=10))
+
+ age = self.session.get_expiry_age(modification=modification)
+ self.assertEqual(age, 10)
def test_custom_expiry_timedelta(self):
- # Using timedelta
- self.session.set_expiry(timedelta(seconds=10))
- delta = self.session.get_expiry_date() - timezone.now()
- self.assertIn(delta.seconds, (9, 10))
+ modification = timezone.now()
+
+ # Mock timezone.now, because set_expiry calls it on this code path.
+ original_now = timezone.now
+ try:
+ timezone.now = lambda: modification
+ self.session.set_expiry(timedelta(seconds=10))
+ finally:
+ timezone.now = original_now
+
+ date = self.session.get_expiry_date(modification=modification)
+ self.assertEqual(date, modification + timedelta(seconds=10))
- age = self.session.get_expiry_age()
- self.assertIn(age, (9, 10))
+ age = self.session.get_expiry_age(modification=modification)
+ self.assertEqual(age, 10)
def test_custom_expiry_datetime(self):
- # Using fixed datetime
- self.session.set_expiry(timezone.now() + timedelta(seconds=10))
- delta = self.session.get_expiry_date() - timezone.now()
- self.assertIn(delta.seconds, (9, 10))
+ modification = timezone.now()
+
+ self.session.set_expiry(modification + timedelta(seconds=10))
+
+ date = self.session.get_expiry_date(modification=modification)
+ self.assertEqual(date, modification + timedelta(seconds=10))
- age = self.session.get_expiry_age()
- self.assertIn(age, (9, 10))
+ age = self.session.get_expiry_age(modification=modification)
+ self.assertEqual(age, 10)
def test_custom_expiry_reset(self):
self.session.set_expiry(None)
diff --git a/docs/topics/http/sessions.txt b/docs/topics/http/sessions.txt
index 0082b75db1..1e043405f4 100644
--- a/docs/topics/http/sessions.txt
+++ b/docs/topics/http/sessions.txt
@@ -250,12 +250,23 @@ You can edit it multiple times.
with no custom expiration (or those set to expire at browser close), this
will equal :setting:`SESSION_COOKIE_AGE`.
+ This function accepts two optional keyword arguments:
+
+ - ``modification``: last modification of the session, as a
+ :class:`~datetime.datetime` object. Defaults to the current time.
+ - ``expiry``: expiry information for the session, as a
+ :class:`~datetime.datetime` object, an :class:`int` (in seconds), or
+ ``None``. Defaults to the value stored in the session by
+ :meth:`set_expiry`, if there is one, or ``None``.
+
.. method:: get_expiry_date
Returns the date this session will expire. For sessions with no custom
expiration (or those set to expire at browser close), this will equal the
date :setting:`SESSION_COOKIE_AGE` seconds from now.
+ This function accepts the same keyword argumets as :meth:`get_expiry_age`.
+
.. method:: get_expire_at_browser_close
Returns either ``True`` or ``False``, depending on whether the user's