Ubuntu Gutsy twill package breaks the showforms command

On one computer named snowball, I installed the ubuntu twill package, then tried to test my webapp:

$ twill-sh -u http://coleridge:8181/login2
==> at http://coleridge:8181/login2

-= Welcome to twill! =-

current page: http://coleridge:8181/login2
>> showforms
current page: http://coleridge:8181/login2
>> show




Login 2

Login 2



current page: http://coleridge:8181/login2
>>

The page clearly contains a form, but twill’s showforms command doesn’t display it. Fortunately, I found this post on the twill mailing list and so I didn’t waste too much time scratching my head. Then on this other box, coleridge, I installed twill using easy_install, and all was well:

$ twill-sh -u http://localhost:8181/login2
==> at http://localhost:8181/login2

-= Welcome to twill! =-

current page: http://localhost:8181/login2
>> showforms

Form name=login2 (#1)
## ## __Name__________________ __Type___ __ID________ __Value__________________
1 user_name text (None)
2 passwd password (None)
3 1 None submit (None)

current page: http://localhost:8181/login2

Sidenote: snowball is my new computer. She is a beaut; a 600mhz Compaq Presario with 60mb of ram, and a hard drive that makes clicking sounds when anything happens. I think Clinton was still in office when she was manufactured. I’d like to thank my son for helping decorate her with some very cool Godzilla stickers.

Photo0250.jpg

Installing on such an old machine meant I had to monkey a fair amount with some kernel modules, which is always a blast, and I am now much more aware of how much every program really costs in terms of CPU utilization and memory footprint.

Funny comic about python

This about sums up my experience:

XKCD Python comic

Absurd nitpick: I’m not a fan of modules that execute code on import. I would prefer that importing antigravity doesn’t automatically do anything, and if I want to use antigravity, then I have to call a function or something like that.

Found a possible error in chapter 7 of the TurboGears book

I bought the TurboGears book about two weeks ago, and I have been working through it. I like the book in general, but I agree with the reviewers on Amazon that complain about the number of errors. I can’t think of another programming book that I’ve read with this many errors.

All of the errors I noticed are little glitchy typographical errors, rather than incorrect theory. The authors really do a good job of illustrating the MVC approach to web design, so I’m glad I bought it.

Anyway, this page lists mistakes found after publication, and the community of readers seems to be doing a good job of helping each other out.

I think I might have found another tiny error. This code appears at the bottom of page 109:

class ProjectFields(widgets.WidgetsList):
title = TextField(label="project", validator=validators.NotEmpty())
client_revenue = widgets.TextField(validator=validators.Number())
project_form = widgets.TableForm(fields=ProjectFields(), action="save_project_test")

I don’t see the point in using both TextField and widgets.TextField. But more importantly, I think the indentation is wrong in the last line. I don’t think project_form is supposed to be an attribute of the ProjectField class.

I think the code should look more like this:


class ProjectFields(widgets.WidgetsList):
title = widgets.TextField(label="project", validator=validators.NotEmpty())
client_revenue = widgets.TextField(validator=validators.Number())

# Moved outside the class.
project_form = widgets.TableForm(fields=ProjectFields(), action="save_project_test")

But maybe I’m missing something. I posted to the TurboGears Book mailing list, so hopefully I’ll find out.

becontrary.com is a neat site built with TurboGears

BeContrary.com is a very clever idea for a site. This debate on going dutch illustrates how the site works. And this is a good discussion of different styles of python templates.

The site’s author, Will McGugan, wrote up a blog post describing his experience with turbogears here. He says he chose TurboGears partially because he had already worked with CherryPy and really liked it. Will made this remark after talking about SQLObject:

Incidently, I don’t like the way that Python ORMs specify the database schema as Python code. Since the schema doesn’t change when the application is running, I would prefer a simple xml definition that would be used by the ORM to dynamically build classes for each table that could be derived from in the model code.

I like this idea, but instead of writing XML, I would prefer to write SQL and have python parse that to build classes.

Is TurboGears dying?

Popularity is not the best indicator of quality, but I don’t like this chart one bit:




I submitted a topic for CodeMash 2008

I attended last year’s CodeMash conference and learned a lot. This year, I submitted a topic. Here’s my description:

Bottom-up programming with IPython

IPython is a vastly improved Python interactive interpreter.

You can start up the interpreter, load in a module, execute a function from that module, then hop from your interpreter into your favorite editor to redefine that function, then go back to the interpeter and run the automatically reloaded function.

If your new code raises an uncaught exception, you can start a python-debugger session right there and inspect the traceback.

With all these tools integrated, you can attack problems by building separate components and then put them together in the interpreter and watch what happens. If you find a bug, you have immediate access to the traceback, so you don’t need to go back into your code and logging or print statements.

Fans of iterative development and using introspection will likely enjoy this talk.

We’ll see what happens.

The python logging module is much better than print statements

A while back, I swore off using adding print statements to my code while debugging. I forced myself to use the python debugger to see values inside my code. I’m really glad I did it. Now I’m comfortable with all those cute single-letter commands that remind me of gdb. The pdb module and the command-line pdb.py script are both good friends now.

However, every once in a while, I find myself lapsing back into cramming a bunch of print statements into my code because they’re just so easy. Sometimes I don’t want to walk through my code using breakpoints. I just need to know a simple value when the script runs.

The bad thing is when I write in a bunch of print statements, then debug the problem, then comment out or remove all those print statements, then run into a slightly different bug later., and find myself adding in all those print statements again.

So I’m forcing myself to use logging in every script I do, no matter how trivial it is, so I can get comfortable with the python standard library logging module. So far, I’m really happy with it.

I’ll start with a script that uses print statements and revise it a few times and show off how logging is a better solution. Here is the original script, where I use print statements to watch what happens:

# This is a.py

def g():
1 / 0

def f():
print "inside f!"
try:
g()
except Exception, ex:
print "Something awful happened!"
print "Finishing f!"

if __name__ == "__main__": f()

Running the script yields this output:

$ python a.py
inside f!
Something awful happened!
Finishing f!

It turns out that rewriting that script to use logging instead just ain’t that hard:

# This is b.py.

import logging

# Log everything, and send it to stderr.
logging.basicConfig(level=logging.DEBUG)

def g():
1/0

def f():
logging.debug("Inside f!")
try:
g()
except Exception, ex:
logging.exception("Something awful happened!")
logging.debug("Finishing f!")

if __name__ == "__main__":
f()

And here is the output:

$ python b.py
DEBUG 2007-09-18 23:30:19,912 debug 1327 Inside f!
ERROR 2007-09-18 23:30:19,913 error 1294 Something awful happened!
Traceback (most recent call last):
File "b.py", line 22, in f
g()
File "b.py", line 14, in g
1/0
ZeroDivisionError: integer division or modulo by zero
DEBUG 2007-09-18 23:30:19,915 debug 1327 Finishing f!

Note how we got that pretty view of the traceback when we used the exception method. Doing that with prints wouldn’t be very much fun.

So, at the cost of a few extra lines, we got something pretty close to print statements, which also gives us better views of tracebacks.

But that’s really just the tip of the iceberg. This is the same script written again, but I’m defining a custom logger object, and I’m using a more detailed format:

# This is c.py
import logging

# Make a global logging object.
x = logging.getLogger("logfun")
x.setLevel(logging.DEBUG)
h = logging.StreamHandler()
f = logging.Formatter("%(levelname)s %(asctime)s %(funcName)s %(lineno)d %(message)s")
h.setFormatter(f)
x.addHandler(h)

def g():

1/0

def f():

logfun = logging.getLogger("logfun")

logfun.debug("Inside f!")

try:

g()

except Exception, ex:

logfun.exception("Something awful happened!")

logfun.debug("Finishing f!")

if __name__ == "__main__":
f()

And the output:
$ python c.py
DEBUG 2007-09-18 23:32:27,157 f 23 Inside f!
ERROR 2007-09-18 23:32:27,158 exception 1021 Something awful happened!
Traceback (most recent call last):
File "c.py", line 27, in f
g()
File "c.py", line 17, in g
1/0
ZeroDivisionError: integer division or modulo by zero
DEBUG 2007-09-18 23:32:27,159 f 33 Finishing f!

Now I will change how the script handles the different types of log messages. Debug messages will go to a text file, and error messages will be emailed to me so that I am forced to pay attention to them.

# This is d.py
import logging, logging.handlers

# Make a global logging object.
x = logging.getLogger("logfun")
x.setLevel(logging.DEBUG)

# This handler writes everything to a file.
h1 = logging.FileHandler("/var/log/myapp.log")
f = logging.Formatter("%(levelname)s %(asctime)s %(funcName)s %(lineno)d %(message)s")
h1.setFormatter(f)
h1.setLevel(logging.DEBUG)
x.addHandler(h1)

# This handler emails me anything that is an error or worse.
h2 = logging.handlers.SMTPHandler('localhost', '[email protected]', ['[email protected]'], 'ERROR log')
h2.setLevel(logging.ERROR)
h2.setFormatter(f)
x.addHandler(h2)

def g():

1/0

def f():

logfun = logging.getLogger("logfun")

logfun.debug("Inside f!")

try:

g()

except Exception, ex:

logfun.exception("Something awful happened!")

logfun.debug("Finishing f!")

if __name__ == "__main__":
f()

Lots of really great handlers exist in the logging.handlers module. You can log by sending HTTP gets or posts, you can send UDP packets, you can write to a local file, etc.

Finally, I’d like to point out that Mike Pirnat has some excellent slides (in PDF format) on logging using the standard python library here.

When to use globals

I am dogmatic about never using global variables. But when people way smarter than me use them, like Brian Kernighan does when he builds a command-line interpreter in that chapter of The Unix Programming Environment, I wonder if maybe I’m being too reluctant.

I was looking at a python module vaguely like this:

def foo():
do_foo_stuff()

def bar():
do_bar_stuff()

def baz():
do_baz_stuff()

def quux():
do_quux_stuff()

I had a bunch of independent functions. I wanted to add logging. I saw two easy ways to do it:

def foo():
logger = get_logging_singleton()
logger.log_stuff()
do_foo_stuff()

def bar():
logger = get_logging_singleton()
logger.log_stuff()
do_bar_stuff()

def baz():
logger = get_logging_singleton()
logger.log_stuff()
do_baz_stuff()

def quux():
logger = get_logging_singleton()
logger.log_stuff()
do_quux_stuff()

In the above code, I would get a reference to my logger object in each function call. No globals. Maybe I am violating some tenet of dependency injection, but I’ll talk about that later. Anyhow, the point I want to make is that the above approach is the way I would do it in the past.

Here’s how I decided to write it this time:

logger = get_logging_singleton()

def foo():
logger.log_stuff()
do_foo_stuff()

def bar():
logger.log_stuff()
do_bar_stuff()

def baz():
logger.log_stuff()
do_baz_stuff()

def quux():
logger.log_stuff()
do_quux_stuff()

All the functions access the logger created in the main namespace of the module. It feels a tiny bit wrong, but I think it is the right thing to do. The other way violates DRY in a big fat way.

So, a third option would be to require the caller to pass in the logging object in every function call, like this:

def quux(logger):
logger.log_stuff()
do_quux_stuff()

This seems like the best possible outcome — it satisfies my hangup about avoiding global variables and the caller can make decisions about log levels by passing any particular logger it wants to.

There’s two reasons why I didn’t take this approach:

  1. I was working on existing code, and I didn’t have the option of cramming in extra parameters in the calling library. So, I could do something like def quux(logger=globally_defined_logger) but I’m trying to make this prettier, not uglier. The whole reason that I wanted to add logging was that I wanted some visibility into what what the heck was going wrong in my app. I didn’t have time to monkey with overhauling the whole system.
  2. I plan to control my logger behavior from an external configuration system. I don’t want to change code inside the caller every time I want to bump the log level up or down. It is the conventional wisdom in my work environment that I face less risk just tweaking a configuration file setting and restarting my app rather than editing my code*.

[*]I suspect that in the final analysis, this belief will be exposed as garbage. But for right now, it seems pretty true that bugs occur more frequently after editing code than after editing config files.

UPDATE: Apparently, I’m not just talking to myself here! Gary Bernhardt linked to this post and added some really interesting points. Also, his link to the post on the origin of the phrase now you have two problems was something I hadn’t heard of before.

Dependency Injection Demystified

I’m building a robot to make breakfast.

def make_breakfast():
    fridge = get_reference_to_fridge()
    eggs = fridge.get_eggs(number_of_eggs=2)
    fried_eggs = fry(eggs, over_easy)
    cabinet = get_reference_to_cabinet()
    plate = cabinet.get_plate()
    add(fried_eggs, plate)

    return plate

This is OK, but I realize my robot needs lots and lots of practice, and I don’t like wasting all my nice eggs and getting all my plates dirty. So, while my robot is still learning how to cook, I want to specify that it uses paper plates and some crappy expired eggs I fished out of the grocery store dumpster.

Continue reading

Google presentation at Clepy on August 6th, 2007

Tonight Brian Fitzpatrick (Fitz) from the Chicago Google office did a presentation for the clepy group on version control at Google. They use subversion on top of their own super-cool bigtable filesystem back end.

We had a good discussion on the merits of centralized vs. decentralized version control. According to Fitz, decentralized systems discourage collaboration. He made the joke, “Did you hear about the decentralized version control conference? Nobody showed up.” He made the point that centralized repositories encourage review and discussion. I agree with that.

Apparently subversion 1.5, which will be released in a few months, will have much improved merging facilities. We won’t need to use --stop-on-copy to figure out where we branched. Also, it will be safe to repeat a merge, because nothing will happen on the second attempt.