The other day, I had a need to walk through all the descendants of a dialog box in PyGTK, so that I could save the contents of each text-entry field to the appropriate database record. After a bit of poking around in the PyGTK manual and not finding the recursive get_children() function that I wanted, I decided to write my own.
def walk_descendants(root): """ Walk through a tree of this object's children, their own children, and so on, yielding each object in depth-first order. """ yield root if not hasattr(root, 'get_children'): return # No children, so we're done children = root.get_children() if not children: return # No children, so we're done for child in children: for widget in walk_descendants(child): yield widget
I use this function to build a dict listing all the widgets in my dialog box, keyed by their names. Then when I need to do something with the OK button, I can use something like
self.widgets['button_OK'] and no matter where it is in the hierarchy, even nested inside several VBoxes and HBoxes, it’s easy to use.
In case others might find this useful, I hereby release this function into the public domain. Use it however you like.
SQLAlchemy is a very useful database-access library for Python. It’s got excellent documentation; but what it was missing until recently was a tutorial. I wrote a step-by-step SQLAlchemy tutorial to fill in the gap. Of course, the day after I wrote it, SQLAlchemy’s author posted the tutorial that he’d been working on, so I just duplicated his efforts. :-)
Nevertheless, it might be useful to someone, so I put it up anyway.
New discovery of the day: Logix. Logix is Python, with macros. Logix is Lisp, with Python syntax. Logix is a programming language that lets you create programming languages. Logix is whatever language you need it to be.
If you’re familiar with Lisp, you already grasp how powerful macros can be. If all you’ve used is Python, let’s take a look at a practical example. Let’s say you’re writing a threaded program, and throughout your code is scattered constructions like:
_lock.acquire() try: print "We have the lock, now doing some work" finally: _lock.release()
Wouldn’t it be nice to have a
synchronized construct that would do the work for you? You could write it as a function, but then you’d have to pass in the code you want to run, which means turning it into another function or a lambda, and that just creates more boilerplate. With macros, you’d be able to do something like this:
defmacro synchronized(lock, codeblock): lock.acquire() try: codeblock finally: lock.release()
Some magic would be required to pass in the codeblock, of course.
Well, in Logix, this is how that macro would be written:
defop 0 "synchronized" "(" $lock:expr ")" ":" $code:block macro lock code lock.acquire() `try: *code `finally: lock.release()
If you’re wondering about the backslashes and backquotes, read the Logix tutorial. It will explain what those do, and in the process introduce you to what Logix is capable of (hint: quite a lot!).
What makes Logix so powerful? The same thing that makes Lisp so powerful: the idea that code is data, and data is code. Which means you can pass around chunks of code to functions, save them in variables, and generally do whatever you want with them. I’ve been meaning to learn Lisp for a while now, but I’ve always been put off by its syntax. That’s because the basic unit of Lisp is the list, and lists inside lists inside lists meant Lots of Irritating Superfluous Parenthesis :-). And I could never get used to writing addition as
(+ 1 2 3) instead of
1 + 2 + 3. But Logix is based on Python, and inherits a lot of Python’s syntax. So instead of parens inside parens, you’ve got blocks based on indentation, and colons at the end of lines signalling that a block is about to start. It’s got the same “clean”-feeling syntax that makes Python so easy to read, but it’s also got the power of Lisp: macros, and the ability to pass code objects (of any kind, not just functions) around. I’m looking forward to playing with it and learning it.
UPDATE, 2005-06-06: The code samples I gave above are for Logix 0.4. 0.5 is going to introduce some changes to the underlying structure (in particular, what “chunks of code” are made of is changing), and so the macro syntax may end up looking a little different. If the code above ends up being wrong, I’ll post an update correcting it.
One of the most exciting things to come out of PyCon 2005 was the WSGI spec. WSGI is a standard that specifies a common interface for Python Web frameworks.
For a full understanding of the interface there’s no substitute for reading the spec. But in my experience, many people are too busy to read specs. So here’s an executive summary of how WSGI works.
WSGI actually specifies two interfaces, one for the server to talk to the application, and one for the application to talk to the server. For the server to talk to the application, it calls a function (which the application supplies) which should accept two arguments,
environ argument will be a dictionary containing the HTTP environment (including variables like
PATH_INFO), and the
start_response argument will be a function.
For the application to talk to the server, it should first prepare any headers it wants to send, then call the
start_response function that it was handed, with a status code and a set of headers. Then it should prepare the body of the response as a list of strings. (An iterator can be used instead of a list). To pass the response body back to the server, it should simply
Once the server receives the list (or iterator) from the application, it simply sends those strings, one at a time, to the client (i.e., the user’s Web browser).
Got that? Here’s what it looks like in Python code:
def simple_app(environ, start_response): status = '200 OK' response_headers = [('Content-type','text/plain')] start_response(status, response_headers) return ['Hello world!n']
There you have it — the WSGI interface in a nutshell. The server invokes the application by calling a function, then sends the function’s return value(s), one at a time, back to the client. Pretty simple, eh?
There are a lot of subtleties that I haven’t covered, of course, such as the contents of the
environ dictionary, or the fact that the application doesn’t have to be a function, but can be any callable object (such as a class). To grasp those, you’ll have to read the spec. But just understanding the concepts presented here is a good jumping-off point to make the spec a lot less mysterious.
Update, 2005-08-15: There’s a simpler way to write my
simple_app example: as a generator. In fact, that’s probably a simpler way to write any WSGI app. Instead of building a list of strings and returning the list, simply use
yield statements, thus:
def simple_app(environ, start_response): status = '200 OK' response_headers = [('Content-type','text/plain')] start_response(status, response_headers) yield 'Hello world!n' yield 'Second line goes heren'