« | » Main « | »

Criminal exceptions

Monday 29 March 2010

We're using socks.py to provide SOCKS proxying in some code at work, and it works great until it doesn't. Then, unfortunately, the author didn't try very hard to help us out.

Recently we got this exception:

GeneralProxyError: (5, "bad input")

Looking into the code, here's where it raises that error:

if (type(destpair) in (list,tuple)==False) or (len(destpair)<2) or (type(destpair[0])!=str) or (type(destpair[1])!=int):
    raise GeneralProxyError((5,_generalerrors[5]))

This is criminal: here is input validation, all of which focuses on a single variable, and when raising the exception, it doesn't include the value of the variable! Ugh.

Error handling is no different than the rest of your product: you need to put yourself in your customer's shoes and think about what they'll need. Then give it to them. Simple.

Dive into HTML5

Sunday 28 March 2010

Mark Pilgrim is good at writing introductions to technical topics, and his latest is no exception: Dive Into HTML5. It's a detailed exposition of the latest additions to HTML.

Some of it seems strangely circuitous, as in the first chapter when he recounts in detail how the img tag got added to HTML in the first place. He has a reason (which is to underscore that HTML was never pure in the first place), but it can seem a long way to go for the lesson.

I've added a few simple tweaks to this site as a result of perusing the changes: input fields of type email and url, and links with rel of author, tag, and license. I haven't gotten into the deeper changes like the new semantic tags <article>, <header> and <time>. Native video is even farther out.

I also learned about OpenSearch which doesn't seem worth it for this site. I can't imagine many people want a special search just for this blog.

And I also learned something new about Internet Explorer in my tangential browsing along the way also: not only does IE interpret these odd conditional HTML comments:

<!--[if IE 6]>
    Special instructions for IE 6 here
<![endif]-->

but it also has a Javascript conditional comment syntax:

/*@cc_on
    alert("Hello IE user (please, please switch)!");
@*/

This leads to this remarkably terse snippet to detect if your code is running in IE:

var ie = /*@cc_on!@*/false;

Will the wonders never cease?

A real Turing machine

Saturday 27 March 2010

In 1936, Alan Turing wrote a landmark paper about what kinds of numbers could be computed: On Computable Numbers. In it, he described what's now known as a Turing machine, which computes with a tape it can scroll back and forth, reading and writing ones and zeros, and transitioning among internal states based on a program.

It was only a thought experiment, a hypothetical machine meant to explore the possibilities of an ultra-simple computer. That is, it was, until Mike Davey built an actual Turing machine. Not an electronic one, but an actual mechanical device that reads and writes ones and zeros on a scrolling tape:

It's a great piece of work, complete with a single-step debugger. The craftsmanship and dedication to the original description are remarkable. And it's amazing to see the juxtaposition of the spool of primitive tape, being driven by an SD card which is commonplace now, but has millions of times the capacity and accessibility.

Ben 12

Wednesday 24 March 2010

Today is my son Ben's 12th birthday. He's always been the artist in the family.

He studies Spanish in school, and one regular assignment is to create flash cards with an illustration on the front and the Spanish word on the back. Of course Ben loves this assignment, and throws himself into it. The kids can choose their own words. Here's a recent card Ben drew, for "integrity":

Integrity, illustrated

I've always admired the ability of cartoonists to capture so much with such simple lines. And Ben has got the knack. I can feel this fellow's indignation at the behavior of the homogenous mocking crowd. I see his courage in standing up to them. I see the power he feels in knowing he is right.

I have no idea where Ben's ability came from, but it takes my breath away to see what comes out the end of his pencil.

Happy Birthday Ben!

SlowNews: a good, too-short idea

Tuesday 23 March 2010

Back in January, Kevin Dangoor had a good idea:

The move toward real-time everything is wrong. We have enough interruptions in our days without having random links and news sprayed at us 24×7. Not to mention that there’s no real thought that goes into real time, and generally very little thought that gets compressed into 140 characters. Length also does not guarantee quality, and too much text can be a waste of time. The trick is to be concise.

[SlowNews is] a weekly post for software developers and technically minded product managers. This is a way to keep up with interesting things that are happening, but through the lens of a weekly view where the uninteresting is edited away, the more interesting is promoted to the top and a bit of commentary ties it all together.

I was very pleased to see Kevin take this on. I find it impossible to stay on top of all the headlines blasting toward me. A news stream that's just a small pace behind the firehose is just what I want. The hype has a chance to boil away a bit, and some connections and reflection have a chance to gain a foothold.

Unfortunately, just a month later, Kevin ended SlowNews. So I'm looking for other sources of thoughtful and measured industry news. Maybe someone else wants to pick up the banner of SlowNews?

What's the point of os.path.commonprefix?

Monday 22 March 2010

Most of the Python standard library is great, providing functions and classes that do their jobs well, often even before you knew you needed the job done (urlsafe_b64encode FTW!)

Which makes my disappointment with os.path.commonprefix all the stronger. This function is worse than useless, it's misleading. Although it's in the os.path module, it knows nothing about paths, working instead character-by-character:

>>> os.path.commonprefix(['/home/ned/cog', '/home/ned/coverage'])
'/home/ned/co'      # That's not an actual path!

The docs helpfully include the warning:

Note that this may return invalid paths because it works a character at a time.

But it should say:

This function is in the wrong place, and has nothing to do with paths, don't use it if you are interested in file paths!

I accepted a patch to coverage.py which used this function, and it looked good. But eventually I turned up cases it got wrong, and had to re-discover what people seem to have understood this for at least eight years. *Sigh*

Two more Lost cakes

Wednesday 10 March 2010

For Max's birthday, we made a cake for when his friends were over on Friday, and one for his real birthday on Tuesday. Because we're all watching Lost, and Max is obsessed with it, both are from the show. One styled after the temple:

Lost temple cake

And the other based on the Dharma logo, with a marshmallow peep as the Swan:

Dharma logo cake

Headhunters say the darnedest things

Tuesday 9 March 2010

I just got a call from an insistent headhunter, so to get him off the phone, I asked him to send me an email with the details of his fabulous opportunity. He said, "OK, sure! Your email address is ned @ Red Hat chelder.com?"

I guess I could create my own Linux distro now...

Max 18

Tuesday 9 March 2010

Today is my son Max's 18th birthday. Although he is not my oldest, in many ways he is my eldest. It's been a pleasure watching and helping him grow into a man, and it will be difficult to let him go off to college in the fall.

He's made various appearances in this blog over the years, making a micro Lego AT-AT and social disturbances at 10, a Flash movie at 11, scientific observations and programming first steps at 13, innovative cinema at 14, a stop-motion movie for French class and an OS X application at 16.

I'm very proud of Max and everything he's done, and I'm looking forward to what's next.

Happy Birthday, Max!

Different, good and bad

Sunday 7 March 2010

One of the challenges in building web sites is coming up with interesting ways of presenting functionality that aren't the same old thing, but are still usable. I came across two sites recently that met this challenge, one well, one badly.

Glyde lets you buy and sell books and DVDs, kind of a cross between Amazon and eBay. Their site is clean and elegant, and although they've chosen a number of unusual presentation techniques, everything works intuitively, sometimes better than you expect.

The home page shows a single horizontal list of popular items. Click one, and you get detail, but the image glides smoothly from its place in the list to the detail box that pops up. Type in the search box, and you get instant feedback in a drop-down list, but it's a complex categorized list that looks more like a product list than a drop-down. Wait around on the page without doing anything, and the horizontal list will scroll along by itself, offering more items for you to consider.

The whole site has a crisp well-thought-out design that's a pleasure to use.

On the other hand, I found HBO's site a confusing mess. The whole thing is in Flash, so it's difficult to link to individual pages. The schedule grid pops up as a window on the page, and then confounds me at every turn. The current time is displayed on a scroll thumb, which confusingly has arrows on it. Click the arrows, and the entire grid is replaced with a spinner progress wheel, and re-displays. Except the time hasn't changed. You have to drag the thumb, but no matter how little you drag it, the entire window refreshes rather than smoothly scrolling, so you have to re-orient yourself each time. The scroll bar has other times and dates displayed on it, but those aren't clickable either, they're just positions you can drag the thumb to.

Click into a particular show, and the description is displayed in too-small an area, requiring scrolling, except there are no scroll bars. Turns out if you hover over the description, it will start scrolling, but you can't control the speed or direction, it just moves. Maybe moving the cursor out of the description will stop it so I can read it? No, that resets the text back to its top position.

Even when playing videos, I'm confused. There's a progress bar that reads 0% when I'm part-way through the clip, and the middle third of the bar is highlighted. The entire site looks to me like a highly-paid designer made a pile of gorgeous Photoshop files, and never considered the dynamic interactions on the site.

Trace function debugging challenge

Tuesday 2 March 2010

One of the more challenging aspects of maintaining a tool like coverage.py is that people use it on complex code bases, and something goes wrong, they report it to me, and I have to dig in and figure out why.

The latest head-scratcher was reported by Christophe Zwerschke as issue 51 on the coverage.py bitbucket tracker. After a few turns to shake out what the issue was, it came down to this: Christophe's code gets the right answer when run without coverage.py, or when run one way with coverage.py, but computes a different answer when run a second way with coverage.py. This is a real mystery, because it is the first report of code actually behaving differently because coverage.py is measuring it.

This has all the markings of a bug in Python, but it could be my fault. In any case, we have to find out. I won't be able to get to it for a bit, and why should I have all the fun anyway? So I'm crowd-sourcing it here: maybe a reader will have an insight into what the heck is going on here.

Here is the file, bug51.py (slightly simplified from the ticket):

class Foo:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return "<Foo %r>" % self.name


class MetaFooList(type):
    def __new__(mcs, cls_name, bases, cls_dict):
        declared = []
        for base in bases:
            declared.extend(getattr(base, 'declared', []))
        for name, value in cls_dict.items():
            if isinstance(value, Foo):
                declared.append(value)
        declared.sort(key=lambda w: w.name)
        cls = type.__new__(mcs, cls_name, bases, cls_dict)
        cls.declared = declared
        return cls


class FooList(list):
    __metaclass__ = MetaFooList

    def __init__(self):
        super(FooList, self).__init__(self.declared)


def test_foolist():
    w = Foo(name="foo")

    class W(FooList):
        foo = w

    w2 = Foo(name="bar")

    class W2(W):
        bar = w2

    foolist = W2()
    print "foolist has %d entries" % len(foolist)

if __name__ == '__main__':
    test_foolist()

Here are the three runs:

$ python bug51.py
foolist has 2 entries

$ coverage run bug51.py
foolist has 2 entries

$ coverage run --timid bug51.py
foolist has 4 entries

An explanation about that last run: the --timid switch forces coverage.py to use a trace function written in Python rather than its fancier one written in C. Ironically, I added the switch as a way to use a gentler tracing mechanism that wouldn't interfere so much with other packages using a trace function, to prevent bizarre problems. But now, it seems to be the source of a real problem itself.

Trace functions can do strange things that can affect the running program, but the ones in coverage.py don't, or at least they aren't supposed to. This test code has plenty of twisty turns, but still, how can it get different answers from two implementations of the same trace function?

Anyone up for the challenge of figuring out what's going on here? If not, I'll get to it eventually, and report back.

« | » Main « | »