Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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).
  • Loading branch information...
commit cd17a24083f3ef17cf4c40a41c9d03c250d817c6 1 parent fc2681b
Aymeric Augustin authored October 27, 2012
40  django/contrib/sessions/backends/base.py
@@ -170,28 +170,52 @@ def _get_session(self, no_load=False):
170 170
 
171 171
     _session = property(_get_session)
172 172
 
173  
-    def get_expiry_age(self, expiry=None):
  173
+    def get_expiry_age(self, **kwargs):
174 174
         """Get the number of seconds until the session expires.
175 175
 
176  
-        expiry is an optional parameter specifying the datetime of expiry.
  176
+        Optionally, this function accepts `modification` and `expiry` keyword
  177
+        arguments specifying the modification and expiry of the session.
177 178
         """
178  
-        if expiry is None:
  179
+        try:
  180
+            modification = kwargs['modification']
  181
+        except KeyError:
  182
+            modification = timezone.now()
  183
+        # Make the difference between "expiry=None passed in kwargs" and
  184
+        # "expiry not passed in kwargs", in order to guarantee not to trigger
  185
+        # self.load() when expiry is provided.
  186
+        try:
  187
+            expiry = kwargs['expiry']
  188
+        except KeyError:
179 189
             expiry = self.get('_session_expiry')
  190
+
180 191
         if not expiry:   # Checks both None and 0 cases
181 192
             return settings.SESSION_COOKIE_AGE
182 193
         if not isinstance(expiry, datetime):
183 194
             return expiry
184  
-        delta = expiry - timezone.now()
  195
+        delta = expiry - modification
185 196
         return delta.days * 86400 + delta.seconds
186 197
 
187  
-    def get_expiry_date(self):
188  
-        """Get session the expiry date (as a datetime object)."""
189  
-        expiry = self.get('_session_expiry')
  198
+    def get_expiry_date(self, **kwargs):
  199
+        """Get session the expiry date (as a datetime object).
  200
+
  201
+        Optionally, this function accepts `modification` and `expiry` keyword
  202
+        arguments specifying the modification and expiry of the session.
  203
+        """
  204
+        try:
  205
+            modification = kwargs['modification']
  206
+        except KeyError:
  207
+            modification = timezone.now()
  208
+        # Same comment as in get_expiry_age
  209
+        try:
  210
+            expiry = kwargs['expiry']
  211
+        except KeyError:
  212
+            expiry = self.get('_session_expiry')
  213
+
190 214
         if isinstance(expiry, datetime):
191 215
             return expiry
192 216
         if not expiry:   # Checks both None and 0 cases
193 217
             expiry = settings.SESSION_COOKIE_AGE
194  
-        return timezone.now() + timedelta(seconds=expiry)
  218
+        return modification + timedelta(seconds=expiry)
195 219
 
196 220
     def set_expiry(self, value):
197 221
         """
2  django/contrib/sessions/backends/cached_db.py
@@ -40,7 +40,7 @@ def load(self):
40 40
                 )
41 41
                 data = self.decode(s.session_data)
42 42
                 cache.set(self.cache_key, data,
43  
-                    self.get_expiry_age(s.expire_date))
  43
+                    self.get_expiry_age(expiry=s.expire_date))
44 44
             except (Session.DoesNotExist, SuspiciousOperation):
45 45
                 self.create()
46 46
                 data = {}
46  django/contrib/sessions/tests.py
@@ -197,31 +197,43 @@ def test_default_expiry(self):
197 197
         self.assertEqual(self.session.get_expiry_age(), settings.SESSION_COOKIE_AGE)
198 198
 
199 199
     def test_custom_expiry_seconds(self):
200  
-        # Using seconds
  200
+        modification = timezone.now()
  201
+
201 202
         self.session.set_expiry(10)
202  
-        delta = self.session.get_expiry_date() - timezone.now()
203  
-        self.assertIn(delta.seconds, (9, 10))
204 203
 
205  
-        age = self.session.get_expiry_age()
206  
-        self.assertIn(age, (9, 10))
  204
+        date = self.session.get_expiry_date(modification=modification)
  205
+        self.assertEqual(date, modification + timedelta(seconds=10))
  206
+
  207
+        age = self.session.get_expiry_age(modification=modification)
  208
+        self.assertEqual(age, 10)
207 209
 
208 210
     def test_custom_expiry_timedelta(self):
209  
-        # Using timedelta
210  
-        self.session.set_expiry(timedelta(seconds=10))
211  
-        delta = self.session.get_expiry_date() - timezone.now()
212  
-        self.assertIn(delta.seconds, (9, 10))
  211
+        modification = timezone.now()
  212
+
  213
+        # Mock timezone.now, because set_expiry calls it on this code path.
  214
+        original_now = timezone.now
  215
+        try:
  216
+            timezone.now = lambda: modification
  217
+            self.session.set_expiry(timedelta(seconds=10))
  218
+        finally:
  219
+            timezone.now = original_now
  220
+
  221
+        date = self.session.get_expiry_date(modification=modification)
  222
+        self.assertEqual(date, modification + timedelta(seconds=10))
213 223
 
214  
-        age = self.session.get_expiry_age()
215  
-        self.assertIn(age, (9, 10))
  224
+        age = self.session.get_expiry_age(modification=modification)
  225
+        self.assertEqual(age, 10)
216 226
 
217 227
     def test_custom_expiry_datetime(self):
218  
-        # Using fixed datetime
219  
-        self.session.set_expiry(timezone.now() + timedelta(seconds=10))
220  
-        delta = self.session.get_expiry_date() - timezone.now()
221  
-        self.assertIn(delta.seconds, (9, 10))
  228
+        modification = timezone.now()
  229
+
  230
+        self.session.set_expiry(modification + timedelta(seconds=10))
  231
+
  232
+        date = self.session.get_expiry_date(modification=modification)
  233
+        self.assertEqual(date, modification + timedelta(seconds=10))
222 234
 
223  
-        age = self.session.get_expiry_age()
224  
-        self.assertIn(age, (9, 10))
  235
+        age = self.session.get_expiry_age(modification=modification)
  236
+        self.assertEqual(age, 10)
225 237
 
226 238
     def test_custom_expiry_reset(self):
227 239
         self.session.set_expiry(None)
11  docs/topics/http/sessions.txt
@@ -250,12 +250,23 @@ You can edit it multiple times.
250 250
       with no custom expiration (or those set to expire at browser close), this
251 251
       will equal :setting:`SESSION_COOKIE_AGE`.
252 252
 
  253
+      This function accepts two optional keyword arguments:
  254
+
  255
+      - ``modification``: last modification of the session, as a
  256
+        :class:`~datetime.datetime` object. Defaults to the current time.
  257
+      - ``expiry``: expiry information for the session, as a
  258
+        :class:`~datetime.datetime` object, an :class:`int` (in seconds), or
  259
+        ``None``. Defaults to the value stored in the session by
  260
+        :meth:`set_expiry`, if there is one, or ``None``.
  261
+
253 262
     .. method:: get_expiry_date
254 263
 
255 264
       Returns the date this session will expire. For sessions with no custom
256 265
       expiration (or those set to expire at browser close), this will equal the
257 266
       date :setting:`SESSION_COOKIE_AGE` seconds from now.
258 267
 
  268
+      This function accepts the same keyword argumets as :meth:`get_expiry_age`.
  269
+
259 270
     .. method:: get_expire_at_browser_close
260 271
 
261 272
       Returns either ``True`` or ``False``, depending on whether the user's

0 notes on commit cd17a24

Please sign in to comment.
Something went wrong with that request. Please try again.