Monthly Archives: January 2008

How to use itertools.cycle to set even and odd rows

I find code like this in a lot of web applications:


list_of_x_objects = ['a', 'b', 'c', 'd', 'e']
for i, x in enumerate(list_of_x_objects):
    if i % 2: htmlclass = "odd"
    else: htmlclass = "even"
    print """<li class="%s">%s</li>""" % (htmlclass, x)

Never mind the print statement. That’s just to illustrate the point without having to explain some template syntax.

The same thing can be expressed with itertools.cycle:


list_of_x_objects = ['a', 'b', 'c', 'd', 'e']
for htmlclass, x in zip(itertools.cycle(['odd', 'even']), list_of_x_objects):
    print """<li class="%s">%s</li>""" % (htmlclass, x)

I see several advantages of the second approach:

  • It’s way more flexible. I can easily switch to a style that repeats every three lines (or four, or five…).
  • I don’t create the variable i when all I really want is a class variable that toggles between values.
  • The second approach avoids the modulus operator. Since I hardly ever use the modulus operator, when I do come across it, I always have to take a second and puzzle out what’s happening.

Notes from Cleveland Ruby meeting on Thursday, Jan 25th

This post contains some python-related information, I promise.

Fun time. Corey Haines explained behavior-driven development and showed some examples using RSpec at last night’s Cleveland Ruby meetup.

As an aside, Corey said “powershell is what the unix command line will be when it grows up” and a thousand angels fell over dead when they heard this blasphemy.

The story-based tests in RSpec seem downright magic. You can write in an english-y syntax:


Given a = 1,
When 
b.foo(a)
Then 
b should return "Hurray"

Or something like that.

I like that RSpec supports a result called “Pending”. This guy writes a good explanation of how it works, and I agree with this remark:

It’s easy enough to rename a test method so it doesn’t execute, but before RSpec I’ve never worked with one where you can mark it as pending and it then reminds you that you still have work to come back too.

I figure that it would be straightforward to add this into nose. Maybe raise a special exception called PendingTest that gets caught differently.

I learned a neat way of using a mock object without having to pass it in as a parameter based on some code I saw last night.

Corey had a couponcontroller that operated on coupon objects. He made a mock coupon object to use with his tests for his couponcontroller. Then, in his test code, he monkeypatched the coupon module so that when somebody said “give me a coupon” he got a mock coupon instead.

I spent a few minutes trying something vaguely like that in python. I’m not sure I like it, but it gets the point across.

I have a file coupon.py:


# This is coupon.py.

class Coupon(object):
    "I'm the real coupon"

    def foo(self):
        print "This is the real coupon"
        return "foo"

And I have a file couponcontroller.py:


# This is couponcontroller.py.

from coupon import Coupon

def couponcontroller():
    c = Coupon()
    return c.foo()

In my test_couponcontroller.py, I want the couponcontroller to use my mock coupon, not the real one.


# This is test_couponcontroller.py.

import couponcontroller

class mockCoupon(object):
    "I'm not the real coupon."
    def foo(self):
        print "Congratulations. You're using a mock."
        return "foo"

def setup():
    # Mess with the module.
    couponcontroller.Coupon = mockCoupon

def test_couponcontroller():
    "couponcontroller should return a string 'foo'"
    assert couponcontroller.couponcontroller() == "foo"

It seems to work:


$ nosetests -s test_couponcontroller.py
couponcontroller should return a string 'foo' ... Congratulations. You're using a mock.
ok

----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

In summary, there’s clearly a lot of smart people in the ruby community, even if they insist on using syntax like


@adder ||= Adder.new

Dear Google

I hate experts-exchange.com. I am tired of getting my hopes up that I found an answer to my problem, and then finding out that they want money before they’ll show me the answer.

From now on, please filter them out of all my future searches.

How to use indexes with SAS datasets

I just came across some old SAS tutorials that I wrote a few years ago, so I’ll be posting them here when I’ve got nothing else to say.

Indexes are an alternative to sorting your dataset or building a format. They speed up any where or by processing.

Creating indexes

You can create an index in a data step like this:


data clm2 (index=(mbrno empssn mi=(mbrno iyymm) ei=(empssn iyymm)));
    set clm1;
run;

The mi and ei are compound indexes, which behave as if you sorted your dataset mbrno iyymm or by empssn iyymm.

You can use proc datasets to add an index to a dataset that already exists:


proc datasets library=saslib;
    modify clm2;
    index create mbrno empssn mi=(mbrno iyymm) ei=(empssn iyymm);

Using indexes

Indexes allow you to merge datasets that aren’t sorted. In the above example, now you can use clm2 just like it was sorted by any of the indexed vars:


data clm_plus_elig;
    merge clm2 mem;
    by empssn iyymm;
run;

This is another example of how to do a lookup.


data d1;
    infile datalines;
    input col1 8.;
datalines;
    101
    106
    102
    102
    103
    103
    104
    105
;

data d2 (index=(col1));
    infile datalines;
    input col1 col2 $8.;
datalines;
    104 ddd
    102 bbb
    103 ccc
    101 aaa
;

data d3;
    set d1;
    set d2 key=col1 / unique;

    /* This block handles bad lookups. */
    if _IORC_ eq %sysrc(_DSENOM) then do;
        col2 = "xxx";
    end;

run;

proc print heading=h data=d3;
run;

And this is the output:

this is the d3 output dataset.       14:43 Friday, March 11, 2005   1

Obs    col1    col2

 1      101    aaa
 2      106    xxx
 3      102    bbb
 4      102    bbb
 5      103    ccc
 6      103    ccc
 7      104    ddd
 8      105    xxx

How to make sure you write more tests

I’ve been writing way more tests for my code lately, and they’ve become the backbone of my development style.

I used to write some web code, then play around with it in the browser and look for something to blow up. Automated testing was usually an afterthought or used for confirmation. Or maybe in some cases I would write tests dilligently at the beginning of a project, but start skipping them as deadlines approached. Following TDD has always felt like sticking to high-school abstinence pledges. I wrote tests because I thought I should do it, not because I wanted to do it.

But now I’ve found a way to make writing tests central to getting my work done. It’s because of the computer I’m using now. It is such a crappy box that it takes about 5 minutes for firefox to start up. Then each page load takes about another 30 seconds at least. In the time it takes to click through three or four pages using firefox or epiphany, my twill scripts can run through about a hundred pages.

There’s a scene in Star Wars: a New Hope where Obiwan trains Luke to use the light saber while blindfolded. Well, he’s not blindfolded, really, he’s wearing a helmet with the blast shield down, but the idea is the same. Luke has to use “the force” to feel out where the floating droid is, rather than relying on his vision.

Anyway, writing web pages with this Compaq Presario 1200 feels kind of like that. It’s too frustrating to check my pages with Firefox. The only way I can make sure that anything really works is to write a test for it.

PS: I wrote this posting with lynx.

Possible bug in 1.0.4b3 tag of turbogears

The /visit/api.py file in the 1.0.4b3 tag of turbogears has this function, starting on line 177:


        def encode_utf8(params):
            '''
            will recursively encode to utf-8 all values in a dictionnary
            '''
            res = dict()
            for k, v in params.items():
                if type(v) is dict:
                    res[k] = encode_utf8(v)

                else:
                    res[k] = v.encode('utf-8')

            return res

If you have a query string like ?a=1&a=2, then params has a key u’a’ that points to a list that contains u’1′ and u’2′. And encode isn’t defined for lists, so . . .

Fortunately, the /visit/api.py file in the branches/1.0 branch already has a fix for this problem, so I ran setup.py develop in my checkout directory and was back in business.

I lost so much time today figuring this out because I kept looking for the bug in my code, rather than in the framework itself. Also, the code works fine as long as the query string doesn’t have more than one value for the same key.

While I’m on the soapbox, I really wish that testutil.py would change this function:


    def tearDown(self):
        database.rollback_all()
        for item in self._get_soClasses():
            if isinstance(item, types.TypeType) and issubclass(item,
                sqlobject.SQLObject) and item != sqlobject.SQLObject 
                and item != InheritableSQLObject:
                item.dropTable(ifExists=True)

to something sort of like this instead:

    def tearDown(self):
        database.rollback_all()
        import copy # Probably don't actually import here, but this is just for illustration.
        x = copy.copy(self.__get_soClasses())  # store a copy of the list.
        x.reverse() # Now reverse it.
        for item in x: # Iterate the reversed copy.
            if isinstance(item, types.TypeType) and issubclass(item,
                sqlobject.SQLObject) and item != sqlobject.SQLObject 
                and item != InheritableSQLObject:
                item.dropTable(ifExists=True)

The whole point of using self.__get_soClasses is that it looks for a list that defines the order to follow when creating tables. You can define soClasses in your model to make sure that your independent tables are created before your dependent tables.

Well, when it comes time to destroy all your tables, you should destroy the dependent tables first.

I posted this about a month ago to the turbogears trunk mailing list already.

Sidenote — if you’re one of the people that are selflessly donating your time to working on turbogears, please don’t take my rants here personally. I’m really grateful that other people are building tools and giving them away, so that I can make a living.

It’s Monster Truck season

My hometown paper is running a story about monster trucks. I’ve been to shows in Texas, and I’ve been to shows in Ohio. The ones in Ohio are fun, but the ones in Texas operate on a whole other level. I suspect my feelings about monster truck shows here match how expat Japanese people feel about USian Sumo wrestlers.

In Ohio, I saw a jeep with a jet engine race around, and a I watched a few big trucks crush a bunch of cars. I have lots of photos of Bigfoots in mid-flight right here. I like this one in particular:

trucks

Meanwhile, at the show in Houston, I saw a guy set himself on fire and jump from the ceiling of the Astrodome. I watched a 20-car demolition derby that went on for an hour.

In Ohio, at the end, a giant robot dinosaur came out bit an old jalopy in half.

In Houston, a guy jumped his car off a ramp and flew into a tower of old custom vans.

Here’s a few pics of the robot dinosaur for those that were too square to be there:
t0

t2

t1

In summary, I like Monster Trucks.