Archive for December, 2007

Python and the clipboard

December 31, 2007

I liked the idea (found via Alex) of modifying clipboard data in place, and decided to steal it for my own use, in python, on win32 and ubuntu. Since it was surprisingly annoying to figure out how to use the clipboard in either case, I’ll post what I ended up with, so that I can find it again myself.

This works with gtk or win32; the latter requires pywin32:

#! /usr/bin/env python2.5

from __future__ import with_statement
from contextlib import contextmanager

    import win32clipboard as wcb
    import win32con

    def WinClipboard():
        A context manager for using the windows clipboard safely.

    def getcbtext():
        with WinClipboard():
            return wcb.GetClipboardData(win32con.CF_TEXT)

    def setcbtext(text):
        with WinClipboard():

except ImportError, e:
    # try gtk.  If that doesn't work, just let the exception go
    import gtk

    def getcbtext():
        return gtk.Clipboard().wait_for_text()

    def setcbtext(text):
        cb = gtk.Clipboard()

def replaceclipboard(fn):
    Modify text on the clipboard.

    fn: a callable object that maps strings to strings.

    >>> setcbtext("This is some text.")
    >>> replaceclipboard(lambda s : s.upper())
    >>> getcbtext()
    text = getcbtext()
    newtext = fn(text)

def _test():
    import doctest

if __name__ == '__main__':

Scranletting down to Ticklepenny Corner

December 30, 2007

Having seen the great 1995 film of Cold Comfort Farm a few times, and knowing it was a parody of a genre that no longer really exists, the wife and I decided to find out just what that genre was. So I picked up a copy of Mary Webb‘s Precious Bane, and well…

It was at a love-spinning that I saw Kester first. And if, in these new-fangled days, when strange inventions crowd upon us, when I hear tell there is even a machine coming into use in some parts of the country for reaping and mowing, if those that mayhappen will read this don’t know what a love-spinning was, they shall hear in good time…

Kester says that all tales, true tales or romancings, go farther back than the days of the child; aye, farther even than the little babe in its cot of rushes. Maybe you never slept in a cot of rushes; but all of us did at Sarn. There is such a plenty of rushes at Sarn, and old Beguildy’s missus was a great one for plaiting them on rounded barrel-hoops. Then they’d be set on rockers, and a nice clean cradle they made, soft and green, so that the babe could feel as big-sorted as a little caterpillar (painted butterflies-as-is-to-be, Kester calls them) sleeping in its cocoon. Kester’s very set about such things. Never will he say caterpillars. He’ll say, ‘There’s a lot of butter-flies-as-is-to-be on our cabbages, Prue.’ He won’t say ‘It’s winter.’ He’ll say, ‘Summer’s sleeping.’ And there’s no bud little enough nor sad-coloured enough for Kester not to callen it the beginnings of the blow…

And that’s just from the first page. I should be keeping a list of old Shropshire words to look up. O ah.

The weird part is that I’m actually quite enjoying the book.

Not having actually read Cold Comfort Farm, I hadn’t realized that it was science fiction, sorta, at least in terms of being set in the future and having videophones and such. Was that some sort of commentary about looking to the future rather than the past? [Golly, that makes it sound way more boring than I’m sure it is…] O ah.

One of Mary Webb’s other books, Gone to Earth, was filmed by The Archers, Michael Powell and Emeric Pressburger, among the greatest of filmmakers. It seems to be available now in some sort of Korean import. Was its heroine the original of Elfine, the little Pharisee of the Forest? (Probably not, I’m only guessing based on a quick summary of Gone to Earth.)

Well, I must be off to clettering the dishes with me old twig now–

The FairTax

December 30, 2007

Here‘s a paper by Bruce Bartlett arguing against the FairTax (via the Volokh Conspiracy‘s Ilya Somin, who has his own Libertarian reservations).

The FairTax people have a rather ad hominem response here to a previous Bartlett article (in part about the FairTax and its roots in Scientology!).

Another incontrovertible piece of evidence that the FairTax is a bad idea: Mike Huckabee and Ron Paul are for it.

For the record, I too think our income tax system is appallingly, wastefully, hideously overcomplicated. But that’s not because it’s an income tax, or because it’s progressive (I’m talking to you, Steve Forbes).  Tax brackets are a trivial complication; it takes a few seconds to look something up in a table and you’re done. The problem is all the damned deductions and different income classes, which came about through a combination of well-intentioned social engineering (which mostly results in unintended consequences) and ill-intentioned special-interest lobbying.  Were I king, I would keep the progressive income tax but get rid of ALL deductions, including our beloved mortgage and state income tax deductions. Everyone would fill out a 1040-EZ.

[Yes, I just said some stuff with no supporting evidence at all. Finding some is left as an exercise. I’m too lazy right now.]

[Also, I admit I don’t know what to do about capital gains taxes, a major complication. Two options I see:

  • Tax capital gains as income. Yes, there are good reasons to encourage long-term investing over short-term. But see above.
  • Eliminate them, and raise corporate taxes commensurately.

I think I prefer the first option.]

It should go without saying that there is no chance at all of any of this happening any time soon, so the whole discussion is really only for theoretical and rhetorical purposes.

UPDATE: I should note that I have no idea whether Bartlett is right about the FairTax and Scientology, or whether that is a completely unfounded smear. The FairTax people say he’s very very wrong. But they would, wouldn’t they?

Django serialization

December 29, 2007

I figured out the django serialization problem I mentioned in the previous post, more or less. With unicode, json serialization needs a utf8-aware stream. XML serialization, oddly, needs to NOT have one (that part I don’t get). The easy workaround is to wrap the output stream in a StreamWriter. Here’s the relevant part of my dump script:

def dump_data(strm, format='json', indent=None):
    Output the current contents of the database as a fixture of the given format
    from django.db.models import get_apps, get_models
    from django.core import serializers

    app_list = get_apps()

    # Check that the serialization format exists; this is a shortcut to
    # avoid collating all the objects and _then_ failing.
    except KeyError:
        sys.stderr.write("Unknown serialization format: %s\n" % format)

    objects = (o for app in app_list \
                    for model in get_models(app) \
                        for o in model.objects.all())
        # Bah!
        # json barfs without a codec
        # xml barfs WITH a codec
        if format == 'json':
            strm = codecs.getwriter('utf-8')(strm)
        serializers.serialize(format, objects,
                stream = strm,
                indent=indent, ensure_ascii=False)
    except Exception, e:
        sys.stderr.write("Unable to serialize database: %s\n" % e)

Upgrading django

December 28, 2007

I just upgraded my website to the development version of django. It has a bunch of new little features I’d like to use; and the next time I change the database I want to try django-evolution, which doesn’t work on 0.96.

It was easier than I had feared. For the website itself, I didn’t run into anything unexpected, just these, all documented:

  • In all the models I changed __str__ to __unicode__; that was a simple substitution.
  • Also in all the models’ fields maxlength went to max_length.
  • I had to add a call to smart_string to my csv view.
  • I’ve found one place I that needed protection from html escaping. The problem was a string containing   in a python file; I wrapped it with mark_safe there, rather than adding a more general but less safe fix to the tag that eventually uses it.

I have a couple of utility scripts that were more of a problem. One needed to be rewritten because of the massive changes to django’s module; the new version is a bit cleaner than the old, so that pleases me. The other is a problem with json serialization, which (at least as I’m (mis?)using it) now seems to have trouble with non-ascii unicode strings. But that I don’t really need (and if I did, xml seems to work fine), so figuring it out isn’t a high priority.

The big change here was obviously unicode. I see the advantage of that in the abstract, but I do have to wonder if it is really a win in my particular case. I have non-ascii (and non-latin1) data, but utf8-encoded strings worked just fine for me. Probably though that’s a reflection of the triviality of the text-processing I do…

UPDATE: Just found another gotcha: urllib.quote doesn’t like non-ascii unicode. Fixed with smart_str.

UPDATE 2: I should RTFM; the correct fix for the first update is to use django’s own url functions. Also, I forgot to mention one thing I had to do originally: fix a typo in a template! 0.96 let this get by:

	{% extends "foo.html" }

The Thirteenth Apostle, cont.

December 27, 2007

I’ve finished and mostly digested The Thirteenth Apostle. I was very pleased to find that the bits that weren’t mentioned in the publicity and blurbs–analysis of the GoJ in relation to proto-orthodox Christianity and, especially the Gospel of Mark–were at least as interesting as the bits that were.

A very quick recap.  In Professor DeConick’s translation and interpretation, Judas is as evil as ever.  More so, perhaps: Jesus calls him “you thirteenth demon,” an appellation of Ialdabaoth, the false god who created the earth; not “thirteenth spirit.”  Jesus reveals the mysteries of the cosmos to him not because he is one of the elect, but to tell him how badly he will suffer.  Note that in both this reading and in the original “good Judas” one of the National Geographic team the disciples (and by extension proto-orthodox/apostolic Christianity) come off very poorly; the real difference is the nature of Judas, who in either case is clearly intended to serves as a literary device, not as any reflection of an historical Judas.

Prof. DeC. writes–speculatively but convincingly, I think–that the GoJ is closely tied to the Gospel of Mark. In each the disciples are, well, stupid, even willfully so.  The author of Mark was likely a follower of Paul attacking the Jerusalem church by attacking its founders and leaders.  A few generations later the author of the GoJ used the same tactic–remaining faithful to the scripture itself–to attack the proto-orthodox apostolic Christians.

In Mark the disciples never do seem to understand who Jesus really is; the closest any of them comes is Peter, in Mark 8:27-29:

…and by the way he asked his disciples, saying unto them, Whom do men say that I am? And they answered, John the Baptist; but some say, Elias; and others, One of the prophets. And he saith unto them, But whom say ye that I am? And Peter answereth and saith unto him, Thou art the Christ.

But even Peter misunderstands Jesus’s true nature, in the very next verses:

And he began to teach them, that the Son of man must suffer many things, and be rejected of the elders, and of the chief priests, and scribes, and be killed, and after three days rise again. And he spake that saying openly. And Peter took him, and began to rebuke him. But when he had turned about and looked on his disciples, he rebuked Peter, saying, Get thee behind me, Satan: for thou savourest not the things that be of God, but the things that be of men.

The disciples never call Jesus “the Son of God.” The only “people” who do are the centurion at his crucifixion–and the demons Jesus exorcises(!)

Which brings us to Judas himself.  In the GoJ the only disciple who recognizes Jesus’ true nature is Judas, himself a demon, or at least possessed or somehow connected with one–and not just any demon, but the archdemon, the false god Ialdabaoth.  The disciples, meanwhile are so hopeless that they are worshiping the wrong God.

What exactly Judas is isn’t clear to me.  Certainly he is closely connected with Ialdabaoth–Prof. DeC. cites lots of evidence in the language and imagery of the gospel for that, much more than “thirteenth demon.”  The phrase “Lift up your eyes and see the cloud and the light in it, and the stars around it,” most clearly: stars are fixtures of our material world, ruled by the Archons (evil angels, basically), not the immortal world of the Aeons (aspects of the true God, more or less).

But Judas himself doesn’t seem to know who he is, and very much wants to avoid his demonic nature and destiny.  Jesus tells him he has no choice: “Already your horn has been raised, and your wrath kindled, and your star ascended…”  All the lessons Jesus has taught Judas will help him not a bit; Jesus just wanted Judas to know how much he will suffer.  Jesus is a bit of a jerk here, really.

Besides Judas’ demonic nature, the Bad Judas translation/interpretation is more consistent than the NG’s Good Judas interpretation in a few other ways.  The really glaring one is sacrifice: the author of the GoJ clearly finds sacrifice appalling, especially human sacrifice.  How then could sacrificing Jesus himself be a good thing?  The author of the GoJ finds the orthodox interpretation of Jesus’ death as an atoning sacrifice abhorrent.

Another problem with the NG interpretation is the concept of authority and “ruling.”  The GoJ’s position, as makes sense in anything Gnostic (*), is that Authority is Bad.  Why then would Jesus promise Judas that he “will come to rule over them,” unless Judas is cursed never to enter the immortal world of the Aeons?

(*) Whatever “Gnostic” means, but that’s another topic.

Ron Paul, Proud Confederate

December 26, 2007

Holy crap! I knew Ron Paul was a loony, but I had thought it was in an endearing libertarian way. It turns out he thinks that Abraham Lincoln was wrong to start the Civil War and that a policy of “gradual emancipation” would have been preferable. That is wrong in so many different ways I hardly know what to say. See the first link above for some details (which barely scratch the surface, but still).

Now I am an actual Southerner. I can’t abide the word “Civil” any more than any other Southerner (*). I talk about “The War of Northern Aggression” and “The Recent Unpleasantness between the Sections.” But the line that the evil Yankees started the thing as a war of economic imperialism just doesn’t hold up in light of even a quick survey of the history. I’ll go even further: the Southern aristocratic culture was evil and had to be destroyed. It would have been nice to have done it without killing 600,000 people and devastating the South, but the Fire-Eaters just couldn’t wait for that.

Oh, one other point: I have heard it argued that the war could not possibly have been about slavery–very few of the southerners actually fighting owned slaves (or at least many slaves), and very few of the northerners really cared (including Grant himself, at least at first!)–or abstract concepts like States’ Rights and Preserving the Union. That misses a simple but important point: the reasons the soldiers were fighting do not necessarily have anything to do with the reasons the war started. Shelby Foote put it well:

For all the talk of States Rights and the Union, men volunteered for much the same reasons on both sides: in search of glory or excitement, or from fear of being thought afraid, but mostly because it was the thing to do.

Oh, and Ron Paul is pretty screwy on economics too. The gold standard??? I suppose that is consistent with being an antebellum southerner…

(*) Bullwinkle reference

Formatting source code

December 26, 2007

How embarrassing! WordPress has what seems to be a nice source code formatter, meaning the stuff with pygments was probably unnecessary; although it may be I like its results better after all. I’ll try the wp one for now. For starters, here’s the function from earlier today:

def getdate(obj, addition):
    Look at the logs to find creation/modfication dates.
    model = type(obj)
    # we need the contenttype
    ct = ContentType.objects.get_for_model(model)
    # now we can look up the logs for this object
    logs = LogEntry.objects.filter(content_type=ct,
    dates = [ for l in logs \
                if not addition or l.is_addition() ]
        return dates[0]
    except IndexError:
        return None 

Syntax coloring

December 26, 2007

In case anyone wants to know: I did the syntax coloring in the previous post using Pygments.

Some django stuff

December 26, 2007

I generally love Django, but it does have some real holes. The worst problem for me is its complete lack of support for database changes. The Django devolppers argue, maybe convincingly, that database evolution is delicate enough that it’s dangerous to automate. But I feel like it’s dangerous enough it shouldn’t all be left to me either. I’m not particularly scared of SQL per se, but I know I could easily get something wrong. Do Rails’ schema evolution things make that easier, or at least less scary?

I just added “created” and “modified” date fields to one of my models, both using Django’s automated date fields, that set themselves to the current date when an object is added/modified. That led to an extra complication: I wanted the real dates for all my already-existing data. Fortunately Django’s admin keeps a log from which all the modification dates can be extracted. Once gotten, they can’t be saved to the database through Django’s normal model inerface–as that would be a modification that would auto-set the modification date, exactly what I don’t want to do.  So that required a bit more SQL.

OK, despite my whingeing the SQL for that was pretty trivial.  I’ll suck it up now. The interesting bit was the python function for extracting dates from logs:


def getdate(obj, addition):
    Look at the logs to find creation/modfication dates.
    model = type(obj)
    # we need the contenttype
    ct = ContentType.objects.get_for_model(model)
    # now we can look up the logs for this object
    logs = LogEntry.objects.filter(content_type=ct,
    dates = [ for l in logs \
                if not addition or l.is_addition() ]
        return dates[0]
    except IndexError:
        return None