MySQL (MySQLdb) sessions on CherryPy
No such module existed, so I wrote one. Using it is pretty simple:
""" Example code using mysqlsession.py """ from mysqlsession import MySQLSession import cherrypy import logging logging.basicConfig(level=logging.DEBUG) sessionInfo = { 'tools.sessions.on': True, 'tools.sessions.storage_type': "Mysql", 'tools.sessions.connect_arguments': {'db': 'sessions'}, 'tools.sessions.table_name': 'session' } cherrypy.config.update(sessionInfo) class HelloWorld: def index(self): v = cherrypy.session.get('v', 1) cherrypy.session['v'] = v+1 return "Hello world! %s" % v index.exposed = True cherrypy.quickstart(HelloWorld())
Download the module: mysqlsession.py
I would publish it formally, but I’m going to see if I can just have it added to the CherryPy project.
UPDATE: I took out the table locking and used InnoDB select-for-update locking.
Making httplib log debug information
As opposed to having it print to stdout.
--- httplib.py.orig 2008-12-16 19:14:07.000000000 -0600 +++ httplib.py 2008-12-16 19:26:20.000000000 -0600 @@ -69,6 +69,7 @@ import errno import mimetools import socket +import logging from urlparse import urlsplit try: @@ -342,7 +343,7 @@ # Initialize with Simple-Response defaults line = self.fp.readline() if self.debuglevel > 0: - print "reply:", repr(line) + logging.info("reply: %r" % (line,)) if not line: # Presumably, the server closed the connection before # sending a valid response. @@ -391,7 +392,7 @@ if not skip: break if self.debuglevel > 0: - print "header:", skip + logging.info('header: %r' % (skip,)) self.status = status self.reason = reason.strip() @@ -414,7 +415,7 @@ self.msg = HTTPMessage(self.fp, 0) if self.debuglevel > 0: for hdr in self.msg.headers: - print "header:", hdr, + logging.info('header: %r' % (hdr,)) # don't let the msg keep an fp self.msg.fp = None @@ -665,11 +666,11 @@ try: self.sock = socket.socket(af, socktype, proto) if self.debuglevel > 0: - print "connect: (%s, %s)" % (self.host, self.port) + logging.info("connect: (%s, %s)" % (self.host, self.port)) self.sock.connect(sa) except socket.error, msg: if self.debuglevel > 0: - print 'connect fail:', (self.host, self.port) + logging.info('connect fail:', (self.host, self.port)) if self.sock: self.sock.close() self.sock = None @@ -702,7 +703,7 @@ # NOTE: we DO propagate the error, though, because we cannot simply # ignore the error... the caller will know if they can retry. if self.debuglevel > 0: - print "send:", repr(str) + logging.info("send: %s" % (str,)) try: self.sock.sendall(str) except socket.error, v:
Worst lock acquisition code ever.
while True: try: lockfd = os.open(path, os.O_CREAT|os.O_WRONLY|os.O_EXCL) except OSError: time.sleep(0.1) else: os.close(lockfd) break self.locked = True
Really people, really? We silently loop until an error goes away? Really?
The Wordy Shipmates
In the unplanned spirit of Thanksgiving, I recently finished Sarah Vowell’s The Wordy Shipmates. Written as a cross between a history book and a mémoire on the Massachusetts Bay, it’s so-named as a commentary on the Pilgrams’ verbose writing style. Vowell has a bookish snarkiness that makes the book worthwhile. Read it.
Decorating your methods
You can read about Python Decorators in the PEP like I had to, or you can just skip to the good stuff.
Python decorators are a way of modifying a function, of quickly wrapping it. They’re sort of like aspect-oriented programming, in that they let you define logic that cross-cuts methods all over your program. Here’s an example that takes a method that returns a list, and converts that list to a CSV file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import csv import StringIO def list2csv(func): def wrapper(*args, **kwargs): listValue = func(*args, **kwargs) fd = StringIO.StringIO() writer = csv.writer(fd) for row in listValue: writer.writerow(row) return fd.getvalue() return wrapper @list2csv def getList(): return [ ('First Name', 'Last Name', 'Profession'), ('Ken', 'Kinder', 'Software Engineer'), ('John', 'Stewart', 'Funny man'), ('Guido', 'Van Russum', 'Smart guy') ] print getList() |
Results in…
First Name,Last Name,Profession Ken,Kinder,Software Engineer John,Stewart,Funny man Guido,Van Russum,Smart guy
Now, you may have seen a few decorators that take keyword arguments, and look like this:
1 2 3 4 5 6 7 8 9 | @list2csv(dialect=csv.exel) <span class="p_default">def getList(): return [ ('First Name', 'Last Name', 'Profession'), ('Ken', 'Kinder', 'Software Engineer'), ('John', 'Stewart', 'Funny man'), ('Guido', 'Van Russum', 'Smart guy') ] </span> |
If you’re like me, you’re tempted to just add a keyword argument, dialect, to the list2csv method. But what’s important to keep in mind is that the text after the @ in your decoration is evaluated to being the decorator. In other words, @list2csv is not a shortcut to @list2csv(). If list2csv is called, it should return a decorator itself. Here’s how:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import csv import StringIO class Tabs(csv.excel): delimiter = '\t' def list2csv(func=None, dialect='excel'): if func is None: return lambda _: list2csv(_, dialect) def wrapper(*args, **kwargs): listValue = func(*args, **kwargs) fd = StringIO.StringIO() writer = csv.writer(fd, dialect) for row in listValue: writer.writerow(row) return fd.getvalue() return wrapper @list2csv(dialect=Tabs) def getList(): return [ ('First Name', 'Last Name', 'Profession'), ('Ken', 'Kinder', 'Software Engineer'), ('John', 'Stewart', 'Funny man'), ('Guido', 'Van Russum', 'Smart guy') ] print getList() |
This is a trick that lets you pass keyword arguments to the decorator. Notice lines 8 and 9, then 20. When this method is the called with a function, it behaves as normal, otherwise it returns a lambda to itself, with the arguments already specified.
PyLucene 2.0 on Ubuntu 5.10
I took me a mailing list post and some banging my head, but here’s how to get PyLucene 2.0 running on Ubuntu 5.10 (Breezy Badger):
Install these dependencies (some from universe):
sudo apt-get install python-dev gcj libgcj6-common libgcj6-dev make zlibc
Then put a file PyLucene needs to be in /usr there:
sudo cp /lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1
Then unpack PyLucene and change its Makefile:
--- PyLucene-src-2.0.0/Makefile 2006-05-27 01:06:51.000000000 -0600 +++ PyLucene-src-2.0.0.mine/Makefile 2006-05-30 12:49:17.000000000 -0600 @@ -118,16 +118,16 @@ #PYTHON=$(PREFIX)/bin/python # Linux (with gcc 3.4.4 and libgcj statically linked) -#PREFIX=/usr/local -#PREFIX_PYTHON=$(PREFIX) -#GCJ_HOME=/usr/local/gcc-3.4.4 -#GCJ_LIBDIR=$(GCJ_HOME)/lib +PREFIX=/usr/local +PREFIX_PYTHON=/usr +GCJ_HOME=/usr +GCJ_LIBDIR=$(GCJ_HOME)/lib #GCJ_STATIC=1 -#LIB_INSTALL=libstdc++.so.6 libgcc_s.so.1 +LIB_INSTALL=libstdc++.so.6 libgcc_s.so.1 #DB=$(PYLUCENE)/db-$(DB_VER) #PREFIX_DB=$(PREFIX)/BerkeleyDB.$(DB_LIB_VER) -#ANT=ant -#PYTHON=$(PREFIX_PYTHON)/bin/python +ANT=ant +PYTHON=$(PREFIX_PYTHON)/bin/python # FreeBSD #PREFIX=/usr/local
Run “make all” then “make install” and you should be good to go!
