Home > Blog

My first YouTube video…

June 12th, 2009

MySQL (MySQLdb) sessions on CherryPy

December 29th, 2008

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.

Python , , ,

Making httplib log debug information

December 27th, 2008

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:

httplib-logging-patch

Python , ,

Worst lock acquisition code ever.

November 24th, 2008

Courtesy of CherryPy:

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?

Python , ,

The Wordy Shipmates

November 24th, 2008

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.

Books

Decorating your methods

March 3rd, 2007

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.

Python

PyLucene 2.0 on Ubuntu 5.10

January 1st, 2007

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!

Uncategorized

Coffeeshop Typewriter

November 25th, 2005

Good times…

Uncategorized