the further adventures of

Mike Pirnat

a leaf on the wind

« Previous Page Next Page »

Python: You're Doing It Wrong

A coworker just showed me this little gem--a maintenance script that's got no author attribution and isn't in source control, so whoever has perpetrated this crime against all that's good and holy remains anonymous and (for the moment) safe from our wrath. I'm so completely taken aback by this--I... I don't know what to say. I just have to share.

#!/usr/bin/env python
import os,sys
ERR=lambda m:W(m+"\n")
PRNT=lambda m:W(m+"\n")
assert len(V)==2,"you must provide a sandbox name"
S("mkdir -p "+VAR)
PRNT("restarting "+SB)
CMD=";".join(['source %s'%J(SBD,'bin/activate'),PST+" serve --daemon --pid-file=%s/ --log-file=%s/sandbox.log %s/sandbox.ini start"%(VAR,VAR,ETC)])
PRNT("All done!")

Weep for us.

Read and Post Comments

A Unified Python Planet

I subscribe to both the official and unofficial Python planet feeds because they've each got some content that's unique to one or the other, but the overlap and duplication has really been bugging me lately. So I suddenly remembered the joy that is Yahoo Pipes and glued both of them together with a unique-ifying filter to eliminate duplicates, and, feeling generous, I stuck a friendlier Feedburner URL around it--you can get it at

It makes me pretty happy so far, except that somewhere in Pipes land I seem to be losing newlines in pre elements (which appears to be a bug in Pipes itself, argh), which is a little (very) annoying when trying to read people's code samples. I may end up replacing the Pipes side with a little bit of Python (a little Feedparser and PyRSS2Gen ought to do the trick) if I get the time later today.

Anyway. I figured I should share it, on the offchance it makes anyone else's life better. (Or if such a creature already exists, let me know and I'll gladly use that instead.)

Read and Post Comments

He Who Rocks and Puts Away Lives to Rock Another Day

The kiddo has had a pretty strong musical interest for a while now, but in the last week or so she's gotten really excited by my Rock Band controllers, which have been hanging out in the corner of the family room, right where they're easy for her to get at if she wanted to. I'm content (thrilled, in fact!) to have her noodling around with my original Rock Band 1 controller (of the woefully busted whammy bar), but I'd like to keep my pair of RB2 controllers in good shape for as long as possible.

So, off we went to Guitar Center to pick up a couple of guitar hooks to hang the controllers on the wall, safely out of reach from curious little hands.

I'm not sure if I'm more embarrassed by buying guitar hooks for my fake guitars, or by the fact that we'd worked up an elaborate tale of how I'd recently inherited a (fictional) ukulele collection (to explain my concerns about whether the hook would be narrow enough to hold the guitar head). Sadly, no questions were asked about my purchase, so we never got to try out the story.

So, here you go--photographic evidence that I am, in fact, pretty much a total dork. Enjoy.

Read and Post Comments

You Nuked My Battlestar!

Pretty much out of nowhere, I suddenly decided that what the world really needs is a Battlestar Galactica-themed version of the classic Battleship game. Besides the obvious cool factor of having a board full of miniature BSG ships, I think there's a lot of depth to be added by tweaking the rules a little bit:

  • The human player can choose to "jump the fleet" rather than firing a shot, allowing the player to rearrange the locations of all of their ships.
  • The Cylon player can return any destroyed ship to the board per turn until the destruction of their resurrection ship, in addition to their normal "take a shot" action. If the Cylon player doesn't have any destroyed ships, they can instead opt to repair one "hit" from a non-resurrection ship per turn in addition to firing a shot, so long as the resurrection ship is still in play.
  • Both sides have a limited number of nuclear weapons which, rather than targeting a single point on the game grid, will have a several-coordinate blast radius. Nukes are only available to their respective players so long as there are battlestars or basestars in play.
  • The Cylon player has a number of sleeper agents in the human fleet; the Cylon player can opt to activate a sleeper instead of firing, which will result in one hit against a human ship of the human player's choosing.
  • The human player may sacrifice a battlestar to destroy a Cylon basestar.
  • After some as-yet-undertermined number of turns, the human player can produce a stealth Viper, which can be relocated on the grid every turn or which can be sacrificed to learn the location of the Cylon resurrection ship.
  • After some as-yet-undetermined number of turns, the human player gets a second battlestar.
  • And, if you're not afraid of Season 4 spoilers, if the human and Cylon player get tired of endlessly killing each other, they can opt to partner up and "go find Earth," at which point the game is over and they both lose.

Cylon raiders and heavy raiders seem like one- and two-hit vessels to me, while the Colonial Vipers and Raptors are probably single-hit ships. Basestars should be relatively large (suggesting a much larger field of play than the standard Battleship grid) and maintain a six-pronged X shape target profile. Battlestars would probably need to be three spaces wide so that the flight pods can take hits too. Obvious choices for other Colonial ships include Colonial One, Cloud 9, Demetrius, the Astral Queen, Daru Mozu (the tylium refinery ship), mining ships, Space Park (the "spinny ship"), and numerous others. Clearly, getting the balance right on both Colonial and Cylon sides would be important to proper gameplay.

The reaction from my coworkers who are also fans has been very positive, so I suspect that if the appropriate corporate behemoths could work out the licensing, they'd at least sell a few units to us. In the mean time, if you feel like giving it a whirl, go for it! The rules definitely need some fine-tuning to make sure gameplay is properly balanced, but they should be at least a good start. If you do end up trying it out, I'd love to hear how it went.

So say we all!

[Edit 7/14/2008 @ 23:19] The collective unconscious appears to have reared its ugly head--turns out I'm not the first to have this idea.

Read and Post Comments

Reconciling Leopard and the Brother 5070N Laser Printer

Once upon a time, I upgraded to Leopard on my Mac Pro, and, though I did not mention it at the time, something in upgrade land totally pissed off my Brother 5070N laser printer.

I'd bought the printer in the first place because it was one of the first to support Bonjour (née Rendezvous, née Zeroconf) networking. With good ol' Tiger, it Just WorkedTM, and all was milk and honey as far as printing went in my home. But noooo, it didn't like the hoity-toity, super-duper-greatest-thing-since-sliced-bread Leopard attitude, and just spat out endless reams of cryptic stack dumps instead of, say, directions to wherever I was in a hurry to leave for. I poked around a little, checking for new drivers and all that sort of common sense stuff, and found that even Brother's website claimed that the drivers were bundled with Leopard and that there was nothing for me to download.

I never did get around to figuring out the problem at the time, and being a sleep-deprived and very busy new dad it unfortunately hasn't been much of a priority. Somehow I've learned to live with six months (!!!) of not being able to print a damn thing. And worse, I've had to hold off on upgrading my wife's machine, which has kept her from being able to enjoy the goodness of automated Time Machine backups.

I finally got fed up with it today and decided to finally sort things out once and for all. I even indulged my inner noob and followed Brother's directions, even though it meant assigning a static IP to my printer and dropping it back from the awesomeness of Bonjour to the semi-awesomeness of old-school IP printing. It turns out that, even though no one says it anywhere, that was the key. So, here's a bit of advice for future Googlers: the 5070N will not print correctly using Bonjour under 10.5. You want the CUPS driver and the "HP Jetdirect - Socket" protocol. Then poof! It's all happy again.

Now to go about breaking upgrading Liz's laptop...

Read and Post Comments

Hopefully Minimizing Wheel Reinvention

Dear Lazyweb:

I have a number of programming itches that I'd like to scratch that are just slightly large enough that I'd really love to just use something that already exists (if available). I'd spend a while digging around, but, well... I'm lazy, and I'm busy. So hopefully some of you have suggestions. I am looking for:

  • an MSN Messenger client library (preferably in Python)
  • a Twitter client library (preferably in Python)
  • a solution for cross-posting between LiveJournal and Wordpress (either direction) that supports (or could be made to support with a minimum of pain) multiple LJ blogs on one end and multiple WP users on a shared blog (not that my wife really posts that much any more) on the other
  • a hosting provider that's friendly to IM bots and is affordable (for some value of "affordable" that I have yet to precisely define, but which in all likelihood simply means that it won't cause marital unrest)

I may award bonus points if the MSN and Twitter suggestions are both written against Twisted. I know Twisted's got some MSN support, but I've not looked into it too closely and was a little disappointed by the state of the official docs and examples.

I currently host with WebFaction and though I'm normally entirely satisfied with them, I seem to recall that at one point they frowned on running IM bots on their shared hosting platforms, although I can't immediately find anything expressly prohibiting it in their terms of service, AUP, knowledgebase, and support forums.

Thanks in advance!

Read and Post Comments

Wait, How Old Is My Kid Again?

The thing about being a relatively new parent is that life very quickly becomes a complete blur, and after a certain point you've no sense of what day it is, let alone how many weeks old your little bundle of joy is. This makes life tricky, since there are certain milestone weeks that are usually the harbingers of sudden shifts into higher levels of fussiness and sleep regression.

So what's a frazzled dad to do?

Well, I do have Python, and I seem to have Google Reader open an awful lot, and cron jobs are a lot better at remembering to do things than I am... So here's my fifteen-minute solution that I whipped up the other week in between putting Claire down for her morning nap and getting ready for work. (File names and URLs have been changed to protect the innocent.)

#!/usr/bin/env python

import datetime
from dateutil.rrule import rrule, DAILY, WEEKLY, MONTHLY
import PyRSS2Gen as RSS2

# You'll want to change all of these values, obviously...
KID_NAME = u'Claire'
BIRTHDAY = datetime.datetime(2007, 9, 10, 21, 57)
FEED_URL = 'http://yoursite/kids_age.xml'
FILENAME = 'your_path/kids_age.xml'

def periods_between(freq, start_date, end_date):
    rr = rrule(freq, dtstart=start_date)
    periods = len(rr.between(start_date, end_date))
    return periods

def format_entry_body(months, weeks, days):
    body = """<h1>Today, %(kid_name)s Is...</h1>
        <li>%(months)s months</li>
        <li>%(weeks)s weeks</li>
        <li>%(days)s days</li>;
    <p>They grow up so fast!</p>"""
    kid_name = KID_NAME    # so we can cheat with locals()
    return body % locals()

def make_rss(body):
    now =
    # Add a hash component to the item link so that the RSS reader
    # will recognize this as today's new entry...
    item_url = FEED_URL+'#'+now.strftime('%Y%m%d')
    rss = RSS2.RSS2(
        title=u"How Old Is %s?" % KID_NAME,
        description=u"How old is %s in months, weeks, and days" \
            % KID_NAME,

        items = [
                title=u"How old is %s today?" % KID_NAME,
    return rss

def to_xml(rss):
    xml = rss.to_xml()
    # Make our xml at least a tiny bit human-readable
    xml = xml.replace('><', '>\n<')
    return xml

def main():
    now =
    months = periods_between(MONTHLY, BIRTHDAY, now)
    weeks = periods_between(WEEKLY, BIRTHDAY, now)
    days = periods_between(DAILY, BIRTHDAY, now)
    body = format_entry_body(months, weeks, days)
    rss = make_rss(body)
    xml = to_xml(rss)
    f = open(FILENAME, 'w')

if __name__ == '__main__':

You will, of course, have to install dateutil (via easy_install) and PyRSS2Gen (the old-school tarball way) so that they can do the heavy lifting for you.

Then all that's left is to cron it to run daily, and point your favorite RSS reader at the feed. Voila! You're on top of exactly how old your kid is, and quickly on your way to becoming Parent of the Year.

Read and Post Comments

The Shell Meme

Since everyone else is doing it...

$ history|awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head
145 ls
143 cd
136 vim
108 svn
90 jobs
65 %1
50 %2
47 nosetests
47 less
21 grep

%1 and %2 are usually me hopping back into backgrounded vim sessions. jobs is me trying to remember what all I've already got open for editing. The other things should be pretty self-explanatory. :-)

Read and Post Comments

Google App Engine Set to Rock My Socks

Google App Engine seems pretty freaking sweet to me. In short:

  • write apps in Python
  • deploy on Google's infrastructure
  • access to existing Google goodness like BigTable, email, and authentication
  • free account can use up to 500MB of storage and serve ~5M page views/month
  • non-free accounts coming soon
  • can upload additional modules as long as they fit the sandbox rules

Unfortunately the beta test pool filled up almost immediately, so I don't get to play with this yet... But it's definitely exciting that Python's in such a spotlight lately.

And check out the video of Guido van Rossum talking about App Engine...

Read and Post Comments

Processing PyCon 2008

Originally uploaded by mikepirnat.

The security line at O'Hare was almost non-existent, so now I've got a bit of time to kill and (since "free wireless network" doesn't seem to want to give me any DNS) have the laptop open, it's probably time to digest and process my PyCon experience.

Overall, I felt strangely disconnected this year. I didn't end up dining with any of the circles I'd overlapped with in years past, didn't go to any parties, didn't stay up late hacking on personal projects, didn't hang out on the IRC channel (thanks a lot, wonky wi-fi), didn't have a presentation to worry about, and didn't end up being able to wake up in time to get my name on the list for Lightning Talks. Heck, since I didn't have the laptop out much, I barely even took notes this year.

What I did do was shoot a lot of photos, some of them acceptable, nearly filling my 2GB card over the course of the conference. I've only had time to upload one as I just haven't had the time, motivation, or energy to sort through everything at the hotel. (And it's not like uploading via the sippy-straw of the hotel's in-room wireless would have been terribly practical either.) I enjoyed briefly meeting Ted Leung before the opening keynote, and was amazed (and somewhat intimidated) by the number and variety of fancy camera toys he'd brought with him as he performed his duties as official photo dude. A number of folks stopped me and asked me questions about my camera and flash; I tried not to sound like too much of a moron when answering them. The weird thing is that everyone assumes if you are toting a DSLR around that you can't possibly take bad pictures with "a camera like that," when in reality shooting with a DSLR is the fastest way to find out exactly how much you suck at photography. I can get some good (and sometimes above-average) results, but I really have to work at it, so I try to stay humble. Also it helps to never show anyone your bad shots. ;-)

While I'm still on the camera talk, I learned that I need to bring extra batteries for the flash, recharge the camera battery while I sleep or bring a spare, and that I should probably buy a spare memory card so that I don't feel any last-day storage pressures when I've been too lazy to dump things down to my laptop. I've also learned to swallow my pride and kick the camera over to automatic metering when the lighting is tricky and I need to shoot quickly--I have some almost-good shots ruined by camera shake that could have been avoided if I hadn't been trying to be all manly and shooting in full manual with no flash. Finally, a happy discovery--the bad-ass heavy-grade Gorillapod that my wife gave me for Christmas makes an excellent hybrid of monopod (albeit rather short) and grip/brace. I found that I could keep the camera very steady by placing two of the legs against my body and supporting the camera with the third, making it easy to track and shoot moving subjects without too much wobble.

On the dining front, the huge posse of Cleveland folks managed to get out to some tasty meals. On Wednesday night we lucked into an unheard of thirty-second wait for a table at Frontera Grill and enjoyed a meal that simply cannot be described in words. Friday night we (along with Bill Zingler, a compadre from the Turbogears sprint in '06) hoofed it down to Ram, a grill and brewhouse, where the beer and food were pretty good. We didn't stay for too long though as we were greatly outnumbered by a vast sea of douchebaggery--drunken BMW-driving jerks in their sport jackets acting out a sad, strange re-enactment of their college (or more likely high school) days. We rounded things out on Saturday with a visit to the local Giordano's for deep-dish pizza, a first for one of our number, where we proceeded to annihilate their supply of Fat Tire.

Gosh, that's an awful lot of text without really even talking about the conference... Which might in itself be a comment about the conference.

Everyone knows the wireless network was stinky, so I won't spend too much time one that. It wasn't until this afternoon that I was able to even connect in any way approaching reliability. By then, really, there wasn't much point.

It seems like the consensus is that the Lightning Talks really suffered this year from the overwhelming dominance of the (lackluster) sponsor talks, to which I can only agree. It was really disappointing to see so little time available to community speakers during what, to me, is really the heart and soul of PyCon. There were a few gems on Friday and Saturday, but mostly... ho-hum.

And I was underwhelmed by a lot of the presentations too. A lot of things that I thought would be really useful or deep ended up being too light, too dull, or just not well presented. I seemed to have a knack for picking a lot of duds. Even two thirds of the tutorials that I attended (Eggs and Testing) were letdowns, due to the lack of being able to do any of the exercise material thanks to the network (Eggs), and the repetition of material from last year's PyCon (Testing).

The big wins for me were the Advanced SQLAlchemy tutorial (slide runner rocks! and if it's possible to be in love with an ORM, I think I am!), Kevin Dangoor's talk about TG2 and Dojo, and John Harrison's insanely cool Halloween laser-zapping extravaganza, which was probably the most fun presentation I've been to in four years of attending PyCon. The first two will have practical benefit for me in my daily existence, and the latter--complete with head-tracking, 3D VR goodness--was just frickin' awesome. A note to future PyCon presenters when coming up with your proposals--lasers, lasers, LASERS!

I don't mean to be so down on PyCon. I had a good time, I was just exhausted from one end to the next. Exhausted before I even left, exhausted while I was there, and (surprise surprise) exhausted now that I'm home. I did really enjoy meeting folks, networking a bit, and soaking in the vibe... It just didn't manage to leave me as energized as I'd gotten used to, spoiled as I've been by PyCons past. Though stumbling across the excellent performance of "Stairway to Heaven" in the atrium thoroughly lifted my spirits. So few people seemed to even notice that it was almost like a private gift just for me.

I've got about seven hundred photos to wade through to find promising candidates to share; please bear with me as the lucky few take their time to escape into my Flickr stream.

Read and Post Comments

« Previous Page Next Page »