Learn Python

June 2nd, 2006

I have never gotten very good at any of the popular shell scripting languages. Over the years, I’ve dabbled in Bourne sh scripts, Perl, awk, and sed. I was never one of those magical guys who could make anything happen in a few seconds. But I’ve always wanted that to change.

I’ve decided to learn Python. I want a fast-acting Swiss Army Knife at my disposal for splicing together the loose ends of my computer life.

Why Python? I don’t know it well enough to really sing its praises, but a number of influences caused me to veer towards this language (as opposed to say, improving my Perl or picking up Ruby):

  1. A Killer App. NodeBox was the catalyst for this whole pursuit, though it has nothing to do with productivity, per se. I downloaded NodeBox on the recommendation of a friend, and was instantly blown away that such a tool exists at all. NodeBox makes it easy to programatically produce graphics on the Mac, exploiting the Quartz graphics capabilities of the system. Python happens to be the language for driving these amazing dynamic documents.
  2. A Good Reputation. I started dropping Python references among groups of programmer nerds who I respect. Almost universally people either didn’t respond (people like me), or else raved about how great it was. About the only thing I ever hear people complain about with Python is its strict indentation rules. Hey. I’m a C programmer, but I have style. Indentation is OK by me.
  3. Support From “The Man”. I’ll admit it, I am more likely to embrace something if Apple does it first. It’s just easier to get involved and stay involved with a technology when you know that there will be value-added by the most influential company in your little neck of the tech woods. Apple has included Python with Mac OS X as a standard part of the system, and even gone so far as to provide special Python bindings in frameworks like Quartz to facilitate the above-mentioned scripting tricks. I can embrace this language without worrying that its functionality on the Mac will suddenly disappear.
  4. A Decent Tutorial. The biggest roadblock to learning for me is finding the start of a good path. If there is an incremental process I can follow to get better at something and eventually “know it,” then it’s much easier to tackle. The author of Python himself, Guido van Rossum, provides a short-and-sweet tutorial that made it easy for me to get to know Python.

I have a little trick with these “short chapters” tutorials. I keep a bookmark to the “next chapter” in my Safari bookmarks bar, and add reading it to my ToDo list for the following day. When I finish the chapter, I update the toolbar bookmark and wait until the next day. That way the learning is never overwhelming – just a few minutes aday, and it still only takes me a couple weeks to get through the whole tutorial.

This trick is OK, but while I was taking this tutorial, I got annoyed by having to constantly flash back and forth between the web page and my Terminal window. The Python tutorial introduces you to ideas that, if you’re anything like me, you immediately want to try out in the interactive shell. I decided to take a cue from Michael McCracken, who recently produced and distributed a dumbed down web browser just for reading Gmail.

Learn Python is a simple Mac OS X application (GNU License, source included) that puts a web browser and terminal window into one application. The web browser points at the aforementioned Python tutorial on the web, and it remembers the last URL you went to, so you can trust it to remember which chapter you were at when you last quit.

It’s a Python-Tutorial Browsing Machine!

By almost every possible measurement, this project was a “waste of time.” But sometimes you’ve got to make the software you wish existed, just so you know it does. I rationalize the time as well-spent since it sets me up to easily crank out one-offs of a similar vein as I find a use for them. If I was really bored I would probably have added “value added” buttons to the UI for specifically navigating the document structure (e.g. next chapter, etc). But I think I’m done for now. Hopefully most of the bugs are ironed out.

I hope some of you will get some use out of this extremely narrow piece of work. At least it might encourage you to learn Python!

PS: Unhappy with the default version of Python that gets launched? Or wish you could use the tool as a ruby or shell scripting or whatever tool? I haven’t put any preferences in this application, but it would be easy enough to hack the sources. If you aren’t feeling up to hacking the sources, or don’t have the tools handy, you can specifically override the path of the launched tool by editing the file “Localizable.strings” in “Learn Python.app/Contents/Resources/English.lproj/”. Inside this file, change the line:

"/usr/bin/python" = "/usr/bin/python";

That will tell the application to use zsh instead of python. Replace the “/bin/zsh” with whatever you want.

Update (June 3, 2006): The download has been updated to version 1.0.3, which now defaults to a left-right orientation for the web and python shell panes. The setting can be changed back to top-bottom through the preferences dialog.

Update (June 4, 2006): Rodney Ramdas posted a modified version of the application that is targeted at learning Ruby, instead. I’ll probably use it to tackle Ruby, next!

Andrew Stone Responds

May 31st, 2006

I had an off-line chat with Andrew Stone, to see what his reaction was to my recent entry about the design of Videator. He agreed to let me publish his response here as a counterpoint to my pretty strong criticism. He makes some good points and at the end of the day, he’s right: it’s best to download and try it out for yourself.

Thanks, Andrew!


Thank you for all the attention you have lavished on Videator.

I would ask you to consider people’s motivations in dissing both the application and me personally so vehemently. Why was such an emotional response generated by this new application? Should I be flattered that my work is not being ignored? Do I win points for touching raw nerves? ;-)

Working with the metaphor, batshit is an extremely rich source of nitrogen prized by gardeners. My software and the ideas contained therein is organic fertilizer for the software world. And in Jazz lingo, no higher complement than ‘crazy’.

I’m one of the last truly independent developers who has scratched out a living for 18 years innovating ideas which quickly get re-used and popularized by larger, better-funded software houses. I rely on good word-of-mouth to continue to get sales, so of course, getting such negative publicity is painful for more than just the ego.

When a new application comes along that does things that no other application has done before, of course there are going to be complaints about the way we decided to implement it! You have some valid design points of course, I am not attempting to deny that. However the emphasis on the exterior drowns out all the core brilliance of what the application can actually do.

It’s as though no one actually used the application but simply decided to trash it from the screenshots or their personal distaste for my independent status. The power of Videator is that it’s not a “limited choices – canned settings – just click here” kind of app Mac users have become so comfortable with. Those types of applications are easy to apply the design guidelines you mention.

Alas, Videator is breaking new ground and is perhaps outside the comfort zone of the armchair critic. Providing a set of tools to do almost unlimited manipulation of video, Videator takes on a very complex domain. Could the UI be tweaked to better? Certainly.

BTW – for people who don’t like polished metal, there is a switch in Preferences to get Aqua windows…

Why not focus on what’s cool and innovative about the application? I encourage people to download and try it for themselves – it’s free for 2 weeks and then just $49 and free upgrades for life – where new and better UI’s will no doubt emerge, it’s still a deal.

Download it now – or learn more at:http://videator.com

MBP: Good and Bad Apples

May 31st, 2006

This post is part of my MacBook Pro Complaints series. Instead of (or in addition to) linking directly to this post, consider linking to the series link, which includes a summary of all findings to date and direct links to the pertinent downloads that users may find useful. Thanks for reading!

Anybody who’s been following my MacBook Pro saga knows that I’ve had plenty to complain about over the past few months. Heck, I’m sick of hearing me complain. This entry is a compromise: I’ll both complain and rejoice about a few Apple employees I have had the pleasure and displeasure of working with over the past couple weeks.

Part 1: Good Apple

After the disappointment of sending my MBP in for repair, being without it for a week and a half, and then getting it back only to discover that nothing had been fixed, I was reluctant to send it in again. I ended up getting in touch with AppleCare again and ultimately being referred to Apple Customer Relations, which is a great service Apple provides for customers who “fall through the cracks” of ordinary customer care. Basically when you have a bad enough experience, they assign a customer relations person to keep an eye on your case and work with you through (hopefully) an ultimately positive resolution.

Apple Customer Relations is awesome! From the first call with my agent, she made it clear she was listening to me and understood my concerns. There were still very clear boundaries. No, Apple wasn’t going to send me a new computer. No, there are no loaners while the machine is in for repair. No, Steve Jobs will not take me to Disneyland. But within those boundaries she worked with me to try to find compromises that might make my life easier. She never questioned the legitimacy of my complaints (part of this is because they are not technically trained, but part of this is clearly because it’s bad business to tell your complaining customers that they are wrong).

I’m still so frustrated about the whole ordeal with my MacBook Pro, but the fact is, Apple is still talking to me. Apple is still trying to help. They are a big company and as such have secret support agendas, and have to avoid admitting when something is wrong even if they know it. Etc., etc., etc. But the are many, many companies where somebody with my number and severity of complaints would simply fall off the end of the support line. We’re sorry. Goodbye. I am at every step of the way afraid that I may be near the end of my support rope, but so far Apple has surprised me with their willingness to keep talking and acting. (While I’m handing out kudos, another company I’ve dealt with recently, TomTom, has excellent support on par with Apple’s).

When I spoke with my Customer Relations representative on May 23 (two days after my birthday!), I agreed to try bringing my computer into the local Apple Store. The idea was that instead of making me wait for the shipping to and from Texas for another round of repairs, I would bring it into the store where a capable technician could do most if not all of the part swapping that a specialist in Texas might do. I was skeptcial, but it was worth a shot. She comforted me by letting me know that she would be watching the progress and follow up with me about the results of the experience.

I wanted to avoid giving up my laptop for another week or more, so I went for it. I decided it was worth it to go along with this idea because it was virtually risk-free, and the time it would take to zip over to the Apple store was much less than the time it takes waiting for DHL to arrive, transit time, etc.

Part 2: Bad Apple

The worst part of any customer support ordeal is the stress of wondering whether you’ll make yourself clear. Whether they’ll respond politely to you. Whether they’ll understand what’s really going on. And whether they’ll actually agree with you that it needs to be fixed.

I took a deep breath on the afternoon of May 24, mentally prepared to make my case as convincingly as possible. The Apple store is the worst place in the world to complain about noise problems, because the blasting music makes every single machine in the store sound absolutely dead silent. (For any noise complaint, they take your machine into the back room where you can’t demonstrate to them how the noise varies or under what circumstances it most affects you). I knew I was up against a tough challenge, but I tried to be optimistic that I would get a Good Apple.

I checked in at the Genius Bar and waited with my buzzer. This was cool. It’s like waiting for a meal at Chevy’s or something. It went off in just a few minutes after I had arrived. So far, so good! Nice work, Apple Store. I met my “Genius,” who greeted me with a sort of contemptuous glare combined with a saccharine mumble of “What can we do for you today?” I explained that I had been sent by customer relations, that there were a few problems of varying priorities, and that the machine had already been sent in once for repair. I sort of waited for him to make the next move, expecting that he might want to glance at my record in his computer, since it showed a lot more information than I could reliably reiterate all at once. “Why don’t you just tell me what’s going on?” he said sort of impatiently.

OK, I plopped my MBP down on the counter and opened it up. I began explaining that I was most surprised that at least the brightness-related buzzing wasn’t fixed, because it’s pretty well-established that this is due to an inverter board problem. As I was talking he acted like I wasn’t there, and raised his black bic pen towards my computer. Using the ink-side tip of the pen, he reached into a corner of my screen’s display and flicked out a piece of dust or something. What are you doing to my computer, you freak?! I paused and when he was done sort of continued explaining. He seemed pretty bored. He finally said something along the lines of what did I expect for being on the “bleeding edge?” I put bleeding edge in quotes because it’s the only part I can guarantee was verbatim a quote from his mouth. He basically echoed that lame user sentiment that you “get what you pay for” when you choose to buy an early rev product. An Apple representative! Telling me that I was on his company’s bleeding edge!

I got a little bit emotional because, after working so many years at Apple, I hate seeing Apple store employees behave in a way that reflects poorly on the company. I explained to him (probably to his great boredom) that I didn’t feel like it was appropriate to classify me (and thousands of others) who made early, strong commitments to Apple’s new architecture as “bleeding edge.” Needless to say he didn’t see the error of his ways at all and insisted that you’ve got to expect a few things to be wrong in a first revision of a machine.

That was the beginning of a relationship that only went downhill. He finally agreed to take my MBP into the “back room” to listen to the noises for himself. He came back and announced that “there’s nothing wrong with the inverter and the CPU whine is within spec.” He handed me my MBP and sort of waited for me to leave, I suppose. I wanted more clarification. Nothing wrong with my inverter? Didn’t you hear the noise? He said that there was no inverter noise and what I was hearing was the CPU whine coming from different sides of the computer. Well, that’s totally inconsistent with my understanding of the inverter noise. Since it goes away and comes back with the brightness, I had to assume it’s inverter-related. In my pessimism I had more-or-less expected the CPU whine complaints to be dismissed, but the inverter noise! I know people who have had this one fixed! At least fix this, Apple. You know how, even!

Another minute or two of trying to get him to agree that we were talking about the same thing. I suggested that maybe I needed to let the machine warm up before the noise is loud enough. It’s difficult because, as I said I’m trying to get him to acknowledge unacceptable noises while Gwen Stefani is blaring on the stereo. He agrees that if I want to “hang out for 20 or 30 minutes” then he’ll listen again after it warms up.

Speaking of warming up, I thought I’d ask about the heat issue before I lost his attention, and that lasted all of about 15 seconds. “If the MBP gets too hot, it will shut down. If it’s not shutting down, there’s nothing wrong with it.” Well, that’s an interesting way of looking at it. Let’s say the maximum heat is 100C. By the Apple Store’s logic that means my computer can be at 99C all the time, while somebody else’s machine is at 60C all the time. We’re both “in spec,” but my hands are forming heat blisters.

So I hang out for 20 or 30 minutes, and then go back to the podium. While I’m waiting another MBP owner comes in, and starts chatting with another Genius. He’s complaining about the heat. The Genius he got is a lot more friendly and explains that unfortunately they can’t do any testing here in the store. They would have to send it away for testing, and that would take a week or two. The customer seemed somewhat satisfied by the response, thanked the Genius, and left the stoer.

I hang out for another 15 minutes or so while he refuses to acknowledge that I’m there. Finally, when another Apple Store employee asks if I’m being helped, I say that I’m “just waiting for him to have a free moment.” Five minutes later he is back in the “quiet room” (who knows how quiet even that room is) with my MBP.

He emerges. Hands me my MBP, and declares, “Both I and a coworker agree that the noise is within spec.” OK. You and a coworker. So this was a hint to me that the “spec” might be a subjective test. I tried to ask whether there was some mechanical test they perform, or whether it’s just based on their own personal hearing. He looked at me sternly and said “I can’t tell you, OK. I’m sorry.” He had a habit of saying “OK” habitually in that patronizing way, almost like the “mmkay” guy on South Park.

All this time I had been on my best behavior. I really tried to avoid calling him on his rudeness and refusal to listen carefully to my complaints. But now that the end was nigh I took the opportunity to give a little rant about how I didn’t think the machine as-is meets the criteria of a professional, $2500 machine. I complained that if Apple’s spec allows user problems to be dismissed so cavalierly, then it was a real shame for the company and its customers. At this point a quiet young woman who had been sitting at the Genius Bar for a few minutes turned to me and said empathetically, “I had six stuck pixels. They said the limit was 7.”

I commiserated with the woman for a minute and wished her luck. At least she has a number to be angry about. I just got an arrogant jerk who can’t even convince me that he understands what the problems with my machine are, let alone if or why they are “within spec.”

Part 3: Good Apple

My visit to the Apple Store almost ruined my day. I went to the store straight after picking up one of my best friends from San Francisco, who was in town for a few days. The last thing I wanted was to put a damper on his visit just because my crappy computer was never going to be repaired. He is a Mac fanatic and was just excited by the fact that we’d been in the Apple Store long enough that he’d authored a blog entry in the time he was waiting. “My first blog entry written in the Apple Store!” he said proudly as he shut his (quiet, cool, lovely) iBook G4 up and packed it in his bag.

I wasn’t looking forward to my next call with customer relations. As nice as she was, she had hinted that if the Apple Store decides there’s nothing wrong, then there might be nothing she could do. I had built myself up over the past few months to perhaps ultimately have to live with some flaws, but the screen buzzing was definitely not one of them. Pizza for dinner and watching episodes of The Office made things quite a bit better. I didn’t even take the MBP out of its case.

The next day, I got a voice mail on my cell phone while I was at the gym. It was my customer relations agent, and she sounded concerned. “I just wanted to check in because I’m looking at your case and I don’t see any repair ticket. I hope everything went OK at the store yesterday.” I called her back on Friday but got her machine. I said I was disappointed with just about every outcome of the store visit. Both the treatment from the “Genius” and the ultimate outcome. At this point I figured it might be the end of the road, so I said “I guess I might be out of luck, but call me back if you want to hear more about my experience at the store.”

Several days passed. It was Memorial Day weekend and all that. I was pretty sure I would hear from her again, but also slightly concerned that maybe that was it. Today she called and asked how I was doing. “I’m doing pretty good,” I said. I always say that because in reality, I am doing pretty good. The MBP can’t take that away from me! She asked me to tell her what happened at the store. So I basically told her everything that I’ve typed in this blog entry, minus the part about pizza and The Office.

To my great satisfaction, she agreed that the store employee had behaved inappropriately. I guess if nothing else, the fact that I got a turd for a Genius may have helped me gain some empathy from the relations agent. She offered to go back to “Plan B” which is me sending the machine back to Texas for another round of repairs. At this point I’m exhausted, don’t want to see another Genius for a long time, and would really like to have that buzzing fixed. If the whine doesn’t get fixed, I’ll just have to come to some compromise of running QuietMBP and losing battery life. But the buzzing, and if at all possible, the heat. Those fixed would be effing fantastic! As my frustration has risen over this whole affair, my expectations have plummeted accordingly.

She explained that she was going to transfer me to a “product specialist” who is a kind of hardcore customer service agent who works specifically with a particular kind of machine (I think). They want me to talk to him so he can get very specific concrete details into the problem report, and so he can trigger an “engineering seizure” of the machine if it sounds like it will be useful as a case study. She again assured me that she’ll be following the progress of the repair.

The product specialist was polite and empathetic. He also seemed to know what he was talking about, and didn’t pull that “I never heard of that before” crap that some agents do when hearing about any problem whatsoever. He was everything a good agent should be, which isn’t asking so much.

He asked me some very specific questions about the problems. Even took seriously the CPU whine complaint. I told him I was pessimistic about it getting fixed but I know that some people have MBPs that are “much quieter than mine.”

As usual, we’ll see how it goes.

Score for the past two weeks: Good Apples – 2; Bad Apples – 1. Stay tuned for more (but hopefully not too many more!) details.

Pain in the Nib

May 28th, 2006

Anybody who’s spent time with Apple’s Interface Builder (IB) application knows that it’s an amazingly intuitive, powerful tool for designing user interfaces. It’s also a major pain in the ass.

While Xcode has improved by leaps and bounds over the past few years, IB has struggled to keep up. For the most part, it seems that changes to IB have been the bare minimum that would placate the masses (and management). IB had to support Carbon, so they tacked on Carbon support. IB had to support Cocoa Bindings, so they added a new inspector pane. There have been some really cool improvements such as the “Compatibility Checking,” but the number of frustrating shortcomings leave me always hoping that a major renovation will soon come.

My problems with IB wouldn’t be nearly so bad if there were viable workarounds. Many of my criticisms stem from its inability to effectively edit multiple items at once. Many times I find myself repeatedly setting the same properties on an item, or typing highly similarly but mildly deviating bindings into a key value field. The problems I face in IB all the time are the kinds of problems I would have long ago automated, if only there was an easy way.

Nibtool is the command-line counterpart to IB, and new programmers on the Mac often assume that it offers exactly the kind of flexibility I have been wishing for. Here we have a tool that dumps a text version of the objects, classes, hierarchy, and connections in a nib file. Hallelujah! Once I dump it to a text file, I can run some shell script or regular expression replacement on the file and pop it back into the nib, right? Nope, sorry! The man page for nibtool lists only one bug, and it’s a big one:

You cannot regenerate a nib file using the output of nibtool.

The fact that this is listed as a bug has always given me hope that it would one day be fixed. Unfortunately, it appears to be getting fixed at the same pace as all the other bugs and quirks of IB. But when Michael McCracken posted this entry describing a happy discovery in the latest Xcode release notes, I shared his cautious optimism. Nibtool has been updated, and it includes a new pair of options for “importing” and “exporting” object properties from and to an existing nib file:

Nibtool can extract properties into a plist format that can be edited and then reimported into the nib using the new –export (-e) and –import (-i) flags.

Is this it? The holy grail? I have played around with the new nibtool a little bit, and all I can say is we’re closer, but this is by no means an easy or complete mechanism for manipulating the contents of a nib file. The release notes and man page are so vague that it’s difficult to even figure out how to use the new options. I have mostly deciphered the new behavior, and hopefully can clarify things for you by paraphrasing what the new options do.

In each case, the effects of the tool are only to manipulate the instance objects in the particular nib file. The functionality is therefore useless for adjusting things like connections, hierarchy, etc. Think of the nibtool import and export functions as shorthand for “iterate the objects in my nib and do keyed value reading or writing on them.” I think one of the confusions is that the PLISTFILE argument in each case is an input file to nibtool. Output is always to the standard output.

nibtool -e – Takes as input a special-format plist file that specifies a list of Objective-C class names and associated keypaths for values that should be fetched. For all objects in the nib that are of the specified class, this option produces as output an plist file containing the current keyed values for whatever keys you specify in the PLISTFILE.

nibtool -i – Takes as input a plist file of the format produced by nibtool -e. For every object specified in the input plist, this option essentially looks up the object in the nib and sets its value as specified in the plist.

So in a nutshell, you use nibtool -e to fetch a bunch of values as a text file. Tweak the text file as you see fit, and feed it back in with nibtool -i. A major drawback to nibtool -e is that if any object you specify doesn’t respond to the particular key, then the whole deal is called off. So you can’t for instance ask for “bounds” of all “NSObject” and hope to get just the objects in your nib that actually have a bounds property. You have to make sure that for whatever class you specify, every instance is key-value compliant for the given keypath.

So what is the magic format of the first input plist? It’s not too special, and is documented in the nibtool man page, but it is still clunky enough to limit casual use. You basically cannot use nibtool -e for anything useful unless you’ve already taken the time to put together a suitable “input plist” describing what it is you’re looking for. I knew that at the very least I was going to need something to make the input plist easy, so I started with a small python script that produces a plist for the simplest possible fetch: “given one class name and one keypath, fetch the values for all suitable objects in the nib.” This is ugly but it’s my very first python script. Cut me some slack. (Thanks to Gus Mueller for telling me about the os.popen() function, and to Mark Rowe for teaching me about Python’s magic triple-quoting).

#!/usr/bin/env python

import sys, os;

def usage():
    print 'usage: %s   ' % sys.argv[0]
    print 'produces a PLIST file from  suitable for editing'
    print 'keyPath value of all objects of class '
        
# Mild validation of the arguments
if len(sys.argv) != 4:
   usage()
   sys.exit(1)

# Construct a suitable temporary plist for the desired class and keyPath 
newXML = '''\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
 "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>%s</key>
    <array><string>%s</string></array>
  </dict>
</plist>''' % (sys.argv[2], sys.argv[3])

# write it to a temporary file
xmlFileName = '/tmp/com.red-sweater.pythonClassValueHack.plist'
output = open(xmlFileName, 'w')
output.write(newXML)
output.close()

# now run nibtool feeding it the xml file and pointing it at the nib
myResults = os.popen('/usr/bin/nibtool -e ' + xmlFileName + ' ' + sys.argv[1])
sys.stdout.writelines(myResults.readlines())

Paste this code into a python text file and run it from the command line. I called my NibValFetch.py. Now when I cruise over to one of my nib files, I can do something like this:

./NibValFetch.py Preferences.nib NSTextField frame > hacking.plist

That is: get all the NSTextFields in Preferences.nib, and ask for their frame. The file “hacking.plist” now contains a list of all the NSTextField objects in my nib, along with a text representation of the frame for said field. Now if I wanted to make every text field 2 pixels wider or something, I could write a script to modify the hacking.plist file, and then feed that into nibtool -i.

I don’t really have time to delve into this much more right now. I’m not even sure the new functionality will prove very useful, but I figured that somebody out there will find a good use for it if nudged in the right direction. I hope this introduction to the new functionality clears up what it can and can’t do, as well as giving you a clue as to how you might go about leveraging it. If you think up any really clever hacks with it, please be sure to share in the comments!