In case anyone was wondering, I solved this problem. The problem was
that my database mapper imported the psycopg module in code running
under mod_python -- which caused an immediate segfault of the apache
child process, thus leading to no output. When I made the changes to
use pyGreSQL, the code I posted previously worked.
For the archives, this is what I used. This is snipped from my code, no
guarantees it will work for anyone else:
In the database interface (creates and executes SQL statements):
====from db.py====================================
#####
#
# Session Management Methods
#
#####
def create_session(self, key, value):
"""
Insert a new row into web_session with
session_id and session_data .
Arguments are:
key
(string representing the session_id)
value
(string representing the session_data)
Does not return a result.
Note that this method does no conversion on the arguments
except a SQL cast() as text.
"""
insert = {'session_id': key,
'session_data': value,
'session_time': 'now()',
'session_creation_time': 'now()',
}
# Sessions must be unique. Double-check uniqueness.
if self.has_session(key):
self.save_session(key, value)
return
else:
table_schema = getattr(schema, 'web_session')
sql, values = self._make_insert('web_session',
key, table_schema,
insert, 'session_id')
self._execute_action_noresult(sql, values)
def has_session(self, key):
"""
Return a boolean (1,0) result indicating whether or not a
session with session_id exists.
Argument: key (string representing session_id)
Returns boolean.
Note that this method does no conversion on the arguments
except a SQL cast() as text.
"""
return self.execute("""
select exists(select * from web_session
where session_id = %(key)s)""", {'key': key}).fetchone()[0]
def get_session(self, key):
"""
Get the session identified by session_id .
Argument: key (string representing session_id)
Returns db_row{session_id, session_data,
session_time, session_creation_time}
Note that this method does no conversion on the arguments
except a SQL cast() as text.
"""
cursor = self.execute("""
select * from web_session
where session_id = %(key)s""",
{'key': key})
# Make a class to store the resulting row, to allow attr access
R = db_row.IMetaRow(cursor.description)
session = cursor.fetchone()
if not session: return None
else: return R(session)
def save_session(self, key, newvalue):
"""
Save as the session_data in the session identified
by session_id . Also update the session_time.
Arguments are:
key
(string representing the session_id)
newvalue
(string representing the session_data)
Returns the number of rows affected (presumably 1).
Note that this method does no conversion on the arguments
except a SQL cast() as text.
"""
update = {'session_id': key,
'session_data': newvalue,
'session_time': 'now()',
}
table_schema = getattr(schema, 'web_session')
additional_where = """
session_data != %(session_data)s
"""
sql, values = self._make_update('web_session',
key, table_schema,
update, 'session_id',
additional_where)
return self._execute_action_noresult(sql, values)
def delete_session(self, key):
"""
Delete the session referred to by session_id .
Argument: key (string representing session_id)
Does not return a value.
Note that this method does no conversion on the arguments
except a SQL cast() as text.
"""
self.execute("""
delete from web_session
where session_id = %(key)s""", {'key': key})
====================================================
On top of this I created a mapping interface, and appropriate
Sessions and SessionManagers:
==web_sessions.py===================================
try: import cPickle as pickle
except ImportError: import pickle
import quixote.session
from web import shared
class db_session_mapper:
def __init__(self):
self.db = shared.db
def __serialize(self, obj):
return pickle.dumps(obj)
def __deserialize(self, objstr):
return pickle.loads(objstr)
def commit(self):
self.db.commit()
def abort(self):
self.db.abort()
def __contains__(self, key):
return self.db.has_session('%s' % key)
def has_key(self, key):
return self.db.has_session('%s' % key)
def __getitem__(self, key):
sessiondata = self.__deserialize(
self.db.get_session('%s' % key)['session_data'])
return sessiondata
def __setitem__(self, key, value):
newvalue = self.__serialize(value)
success = self.db.save_session('%s' % key, newvalue)
if not success:
self.db.create_session('%s' % key, newvalue)
def __delitem__(self, key):
self.db.delete_session('%s' % key)
def keys(self):
return [(res['session_id'])
for res in self.db.get_sessions()]
def values(self):
return [self.__deserialize(res['session_data'])
for res in self.db.get_sessions()]
def items(self):
return [((res['session_id']),
self.__deserialize(res['session_data']))
for res in self.db.get_sessions()]
def update(self, updates_dict):
for k in updates_dict.keys():
self.__setitem__(k, updates_dict[k])
def get(self, key, default=None):
try:
value = self.__getitem__(key)
return value
except KeyError: return default
class SessionManager(quixote.session.SessionManager):
def abort_changes(self, session):
self.sessions.abort()
def commit_changes(self, session):
self.sessions.commit()
class Session(quixote.session.Session):
def __init__(self, request, id):
quixote.session.Session.__init__(self, request, id)
self.data = {}
self.real_user = None
def set_user(self, user):
if self.real_user:
db = shared.db
user_info = db.get_ellis_user(self.real_user)
if user_info['team_member']:
self.user = user
else:
self.user = user
self.real_user = user
else:
self.user = user
self.real_user = user
self.data._dirty = 1
def has_info(self):
return 1
def is_dirty(self):
# The SQL statement generated assures that only
# changes are saved to the database. Because the
# issue is taken care of there, just alwasy save here
return 1
================================================
Finally, I created a new mod_python handler:
====mod_python_session_handler.py===============
import os, sys
from mod_python import apache
from quixote import enable_ptl
from quixote.publish import SessionPublisher
from web.sessions import web_sessions
sessions = web_sessions.db_session_mapper()
web_session_mgr = web_sessions.SessionManager(
session_class=web_sessions.Session,
session_mapping=sessions)
class ModPythonSessionPublisher(SessionPublisher):
def publish_modpython(self, req):
"""publish_modpython() -> None
Entry point from mod_python.
"""
self.publish(apache.CGIStdin(req),
apache.CGIStdout(req),
sys.stderr,
apache.build_cgi_env(req))
return apache.OK
enable_ptl()
name2publisher = {}
def handler(req):
opts = req.get_options()
try:
package = opts['quixote-root-namespace']
except KeyError:
package = None
if not package:
return apache.HTTP_INTERNAL_SERVER_ERROR
else:
pub = name2publisher.get(package)
if pub is None:
pub = ModPythonSessionPublisher(package,
session_mgr=web_session_mgr)
pub.setup_logs()
name2publisher[package] = pub
return pub.publish_modpython(req)