Repository: web2py/web2py

Issue:
expire_sessions.py in admin app
By default admin app in the dist  has nested directory scheme for session files
but current  expire_sessions.py in the cron directory supports the old all-in-one-directory scheme

So it confuses new customers.  
Possible actions:
- remove this example cron task to examples dir
- update it to match nested scheme
- tune admin app for old plain directory session scheme (admin is not for production - has a little sessions)



Discussion:
I'd go for the second option. Would you post a PR ?


Resolving patch:
diff --git a/applications/admin/cron/expire_sessions.py b/applications/admin/cron/expire_sessions.py
--- a/applications/admin/cron/expire_sessions.py
+++ b/applications/admin/cron/expire_sessions.py
@@ -1,17 +1,20 @@
-EXPIRATION_MINUTES=60
-DIGITS=('0','1','2','3','4','5','6','7','8','9')
-import os, time, stat, cPickle, logging
-path = os.path.join(request.folder,'sessions')
+
+import os, time, stat, logging
+from gluon._compat import pickle
+
+EXPIRATION_MINUTES = 60
+
+path = os.path.join(request.folder, 'sessions')
 if not os.path.exists(path):
     os.mkdir(path)
 now = time.time()
-for filename in os.listdir(path):
-    fullpath=os.path.join(path,filename)
-    if os.path.isfile(fullpath) and filename.startswith(DIGITS):
+for path, dirs, files in os.walk(path, topdown=False):
+    for x in files:
+        fullpath = os.path.join(path, x)
         try:
-            filetime = os.stat(fullpath)[stat.ST_MTIME] # get it before our io
+            filetime = os.stat(fullpath)[stat.ST_MTIME]  # get it before our io
             try:
-                session_data = cPickle.load(open(fullpath, 'rb+'))
+                session_data = pickle.load(open(fullpath, 'rb+'))
                 expiration = session_data['auth']['expiration']
             except:
                 expiration = EXPIRATION_MINUTES * 60
@@ -19,3 +22,7 @@
                 os.unlink(fullpath)
         except:
             logging.exception('failure to check %s' % fullpath)
+    for d in dirs:
+        dd = os.path.join(path, d)
+        if not os.listdir(dd):
+            os.rmdir(dd)
diff --git a/scripts/sessions2trash.py b/scripts/sessions2trash.py
--- a/scripts/sessions2trash.py
+++ b/scripts/sessions2trash.py
@@ -30,18 +30,14 @@ def delete_sessions():
 
 from __future__ import with_statement
 
-import sys
-import os
-sys.path.append(os.path.join(*__file__.split(os.sep)[:-2] or ['.']))
-
 from gluon import current
 from gluon.storage import Storage
+from gluon._compat import pickle
 from optparse import OptionParser
-import cPickle
 import datetime
-import os
 import stat
 import time
+import os
 
 EXPIRATION_MINUTES = 60
 SLEEP_MINUTES = 5
@@ -86,12 +82,12 @@ def trash(self):
                 status = 'trashed'
 
             if self.verbose > 1:
-                print 'key: %s' % str(item)
-                print 'expiration: %s seconds' % self.expiration
-                print 'last visit: %s' % str(last_visit)
-                print 'age: %s seconds' % age
-                print 'status: %s' % status
-                print ''
+                print('key: %s' % str(item))
+                print('expiration: %s seconds' % self.expiration)
+                print('last visit: %s' % str(last_visit))
+                print('age: %s seconds' % age)
+                print('status: %s' % status)
+                print('')
             elif self.verbose > 0:
                 print('%s %s' % (str(item), status))
 
@@ -145,7 +141,7 @@ def delete(self):
 
     def get(self):
         session = Storage()
-        session.update(cPickle.loads(self.row.session_data))
+        session.update(pickle.loads(self.row.session_data))
         return session
 
     def last_visit_default(self):
@@ -155,7 +151,7 @@ def last_visit_default(self):
             try:
                 return datetime.datetime.strptime(self.row.modified_datetime, '%Y-%m-%d %H:%M:%S.%f')
             except:
-                print 'failed to retrieve last modified time (value: %s)' % self.row.modified_datetime
+                print('failed to retrieve last modified time (value: %s)' % self.row.modified_datetime)
 
     def __str__(self):
         return self.row.unique_key
@@ -248,7 +244,7 @@ def main():
             break
         else:
             if options.verbose:
-                print 'Sleeping %s seconds' % (options.sleep)
+                print('Sleeping %s seconds' % (options.sleep))
             time.sleep(options.sleep)
 
 if __name__ == '__main__':


Test patch: