Saturday, January 10, 2009

The messy internals of python.org

This evening I've been trying to get the newly auto-generated PEP Index up and running on the website. At first, I thought I could just update the PEP Makefile. When that didn't work, I tried the website's Makefile. As it turns out, the Makefile is only used for testing purposes not in production. So, I began my journey into the caves of Python's web server.

When a somebody makes a change on the website, a post commit hook records the revision number in a special file. As simple as this sounds, it somehow has to involve invoking a C program that calls a Python script. Every 5 minutes a confusingly named binary, post-commit-svnup-binary (called "post-commit" because it used to run as a commit hook), wraps another Python script to build the website. Instead of using the website's Makefile, this program calls another series of Python programs which read a bit like Makefiles. I tried rewriting those to run my index generator, but I still must be missing something because the new PEP index doesn't seem to have gone live yet. *sigh*

python.org really needs an introduction to DRY.

Thursday, January 1, 2009

MRO magic

Here's some more less publicized evil you can accomplish with metaclasses. Here's a simple example file: (Note that although I'm using Python 3.0, this works with all new-style class supporting versions.)

# mromagic.py
class A(object):

def a_method(self):
print("A")

class B(object):

def b_method(self):
print("B")

class MROMagicMeta(type):

def mro(cls):
return (cls, B, object)

class C(A, metaclass=MROMagicMeta):

def c_method(self):
print("C")


Now let's play with this a little:

>>> import mromagic
>>> mycls = mromagic.C()
>>> mycls
<mromagic.C object at 0x622890>
>>> mycls.c_method()
C
>>> mycls.a_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'a_method'
>>> mycls.b_method()
B
>>> type(mycls).__mro__
(<class 'mromagic.C'>, <class 'mromagic.B'>, <class 'object'>)
>>> type(mycls).__bases__
(<class 'mromagic.A'>,)


How does this work? By overriding mro() on the a metaclass we can define a custom __mro__ for our class. Python will then traverse it instead of the default implementation, which is provided by type.mro().