Titus Brown wrote: > I sat down and implemented simple persistent session stores for Durus, > PostgreSQL, and shelve, as well as a simple directory/file based > session store. > http://issola.caltech.edu/~t/transfer/qx-sessions.tar.gz Hooray! I ran test_session.py with MySQL (see below), Durus, shelve, and directory storage, and didn't get any errors. test_session.py is a Quixote application with a number-incrementing link and login/logout links. Because the store selector is hardcoded in create_publisher(), I had to change it in the source between each run. Observations: - For MySQL, I modified SQLSessionStore.__init__ to take an already-open connection from the caller. This shrinks the method to two lines and eliminates the module's dependency on psycopg. - This code is so much more straightforward and flexible than the default Quixote code I'd consider it a significant improvement. It makes it easy to define additional session stores in the future. - directory_store.save_session() has an extra comma in the dump() call. - Session.is_dirty() is apparently not used anywhere. This means I don't have to subclass Session anymore to use it with persistent stores? Hooray. - Session.has_info(), however, is used. If it returns false but a session exists, the session cookie is revoked with prejudice. - NotImplementedError() is better than Exception("unimplemented"), as has been pointed out. - Since these classes are so small, why not put them all in one module? They can import their pecular stuff in their methods, to avoid the module depending on all libraries. - Locking is a general problem; perhaps hooks belongs in the PersistentSessionStore base class. On the other hand, perhaps it's semantically different for each store. DurusSessionStore and ShelveSessionStore lock the whole table, so they don't need an argument. DirectorySessionStore should be locking the file handle for the specific session. (But different platforms require different implementations, so separate lock/unlock methods would be good.) - SQLSessionStore hardcodes the SQL syntax in the middle of larger methods. While this syntax works for PostgreSQL and MySQL, it would be more portable to have separate SQL-generation methods: def _load_session_sql(self): return "SELECT ..." - SQLSessionStore also assumes the connection is transaction safe. DB-API says you cannot call conn.rollback() on an unsafe connection, yet the method just calls it anyway. It works in MySQLdb (although you may get an "incomplete rollback" error sometimes). I guess all the little SQL databases (SQL lite, Gadfly) are transaction safe so maybe it doesn't matter any more. Do you really need to rollback at the beginning of each method? I read somewhere that the application should give us a separate db connection unrelated to any other database operations in the application. - SQLSessionStore also assumes the .execute() substutions use "%(var)s" syntax. That would fail on some database systems. But since it affects the format of the argument (dict or tuple), perhaps we can't do much about it, since the alternative would be to do the substitution ourselves and have to deal with quoting. - You can use SQL REPLACE to avoid the UPDATE/INSERT 'if'.