Friday 22 January 2010

Best Firefox 3.6 change so far

Tabs now open immediately to the right of the tab of the page you opened them on. Before they would open at the end of the list of tabs, way over to the right. The more you opened, the further they would be away from the current tab with any number of unrelated tabs inbetween.



This is a huge improvement to the way I use Firefox.

Thursday 21 January 2010

Strange class leakage

One of the ways in which code reloading can be implemented in Python, with respect to classes defined within managed scripts, is by updating the existing class in place.

The process resembles the following..

  1. The code reloading framework is started up, loading a main copy of every script file registered with it.
  2. The user modifies a script file.
  3. The code reloading framework detects and reacts to the file modification.
  4. The new version of the script file is executed into a dictionary.
  5. For every class in the dictionary that already existed..
    1. The original version of the class is retrieved from the main copy.
    2. Each valid dictionary entry in the new class is moved into the original class, overwriting whatever it had. If the entry is a function, it is rebuilt so that its internal func_globals dictionary points to that of the main copy, rather than the new copy.
  6. The new version of the script file is discarded and garbage collected, now that the main version has been updated to resemble it.
It is a lot less legwork than the alternate approach, which is wandering around the references in the garbage collector and replacing references to the original class.

Leakage

I use the code reloading framework in a MUD framework. One of the project's tasks that I am working on at the moment, is locating the commands which a logged in player can execute.

The original approach was to simply iterate over a given namespace and check if one of the contents was an instance of the Command class. However, as there are now multiple namespace locations where commands may be located, I decided to try an alternate approach. Instead I would find use the garbage collector to find all the subclasses of the Command class, and obtain the commands that way.
for class_ in pysupport.FindSubclasses(Command, inclusive=True):
for verb in class_.__verbs__:
if verb in self.verbs:
logger.warning("Duplicate '%s': %s", verb, class_)
continue
Each time I modified the rehash command, I started to see a ghost class appearing in the output of this logging action. So for the umpteenth time, I wrote some code to dig through the referrers in the garbage collector, in order to work out what was holding the references.

Tracking references

By passing the ghost classes to PrintReferrers, I see the following..
5 REFERRERS FOR <type 'classobj'> __builtin__.Rehash 0x20a84b0
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
6 REFERRERS FOR <type 'list'> [ ... ] 0x20ae1e8
5 REFERRERS FOR <type 'listiterator'> 0x1c33110
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x1b1fc88 <frame object at 0x01B1FC88>
SKIPPED/is-referrer-list 0x20a9c10 <type 'list'>
SKIPPED/is-local-frame 0x1b1fe30 <frame object at 0x01B1FE30>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-referrer-list 0x20a96c0 <type 'list'>
SKIPPED/is-local-frame 0x1b1fc88 <frame object at 0x01B1FC88>
SKIPPED/is-local-frame 0x20f7ae0 <frame object at 0x020F7AE0>
5 REFERRERS FOR <type 'dict'> { ... } 0x20aba50
SKIPPED/is-local-frame 0x20ebec8 <frame object at 0x020EBEC8>
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-referrer-list 0x20a96c0 <type 'list'>
SKIPPED/is-local-frame 0x20cc188 <frame object at 0x020CC188>
5 REFERRERS FOR <type 'function'> 0x20a5eb0
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20cc188 <frame object at 0x020CC188>
SKIPPED/is-referrer-list 0x20a9490 <type 'list'>
SKIPPED/is-local-frame 0x20cc330 <frame object at 0x020CC330>
5 REFERRERS FOR <type 'dict'> { ... } 0x20ab9c0
SKIPPED/is-seen-list 0x20a9e90 <type 'list'>
SKIPPED/is-local-frame 0x20cc330 <frame object at 0x020CC330>
SKIPPED/is-referrer-list 0x20a9ad0 <type 'list'>
SKIPPED/is-local-frame 0x20cf078 <frame object at 0x020CF078>
SKIPPED/seen 0x20a84b0 __builtin__.Rehash
I've trimmed some redundant information out by hand. But what it shows, is that the class has a function that has a dictionary, that has a reference to the class. Seeing what the contents of the trimmed containers were, it indicates that the normal func_globals reference is creating a circular reference and keeping the class alive.

All classes leak?

The first thing I did was rule out that this was simply the way that Python worked.

I created a script containing..
class AClass:
def AFunction(self):
pass
And then repeatedly reloaded the class in the interpreter..
>>> d = {}
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> d = {}
>>> execfile("test.py", d, d)
>>> import gc, types
>>> for v in gc.get_objects():
... if type(v) is types.ClassType and v.__name__ == "AClass":
... print v
...
__builtin__.AClass
__builtin__.AClass
__builtin__.AClass
__builtin__.AClass
>>> gc.collect()
12
>>> for v in gc.get_objects():
... if type(v) is types.ClassType and v.__name__ == "AClass":
... print v
...
__builtin__.AClass
So outside of my framework Python does the correct thing.

Conclusion

Some possible reasons for what is going on:
  • My reference printing function is skipping something it shouldn't (not seeing it).
  • How I am calling execfile is creating this circular reference in a way that is somehow different (not seeing it).
For now, I will enter a defect and have the new script file clear its dictionary when it is garbage collected, which fixes the problem.

Writing this reference tracking code for the umpteenth time makes me wonder if something similar, but both tested and proven, is out there.

Monday 18 January 2010

Private blogs

On the rare occasion, blogs I enjoy reading go dark. They turn on a private mode, where they add anyone who will be allowed to access it onto a whitelist. A common reason, is to avoid the controversy that their posts may incur. Whether this is negative people adding unwelcome comments, creepy internet stalkers from their past or to hide their opinion from parties who may otherwise take offense.

This is all well and good, but from the viewpoint of a whitelist member, it is inconvenient and awkward. If I want to read their blogs, I actually have to go to them, log in and read the posts in place. You can't add them to Google Reader and have it take care of abstracting away the log in process -- not even when the blogs are hosted by Blogger, which Google also owns. And this means, that it is easy to forget to check out these "dark" blogs. And forget commenting on them, let's say you forget the blog for a month and then coming back comment on a selection of posts made during that last month. Just like a public blog, there's no easy way of knowing if your comments were replied to, but worse still, even if there was a comment feed you couldn't subscribe to it anyway.

I'd love to know there was a way to make Google Reader work with these blogs. How hard can it be? One line of code, right? Their help system works well, and gives me this.

Kohlrabi

Living in Iceland, I bought my vegetables from supermarkets. More often than not, they had been shipped over from another country, and weren't the freshest. However, when I left C.C.P. and went to work for another company, I ended up working with a woman named Disa. Disa had a family farm or something, and they grew their own vegetables there. She brought in to work a variety of strange vegetables that do not appear on the shelves of most stores in New Zealand. Kohlrabi was one of these.

Back in New Zealand, I had pretty much forgotten about kohlrabi. But most of my fruit and vegetable shopping is done in an asian supermarket, as they tend to have prices that are significantly lower than those at a mainstream supermarket like Foodtown. In the asian supermarket, there are a lot of vegetables that are simply labeled with signs in Chinese and a price. Mostly I ignore these, on the assumption they are likely imported from the polluted parts of China I am always reading about. In this case, I caught a glimpse of, and recognised kohlrabi. Now I always try and buy a few when I am in there, as a snack. On this shopping trip, the price was $1.49 NZD each.

An uncut kohlrabi with a mug to give an idea of its size.

2010-01-18 - Kohlrabi - 01 - Size

The cut and sliced kohlrabi, accompanied by my sword which I have aptly named "Fingerslicer." My father who used to be a butcher always says, "don't cut on plates, it is the quickest way to make a knife blunt." I make a point of cutting things on ceramic plates with Fingerslicer, in the hope that one day it will stop.. slicing into my fingers. I tell myself it is easier than learning how to use a knife properly.

2010-01-18 - Kohlrabi - 02 - Cut open

They taste like a combination of turnip and radish. Where a turnip tastes like it needs to be cooked before it should be eaten, the kohlrabi does not. Where a radish is often too hot or sharp in the same way as horseradish, kohlrabi is not. They make a satisfying snack, cool and refreshing. In some ways it reminds me of eating apple, but without the sticky juices and cloying sweetness (or acidity and sourness in the case of a granny smith).

Actually now that I think about it, when I went visiting organic markets with Liza in Atlanta, on one occasion I also stumbled across kohlrabi there. And coincidentally, the girl selling the produce mentioned that she had recently travelled over to New Zealand and worked growing them among other things.

Ernest Adams minty choc delight cookies

My closest supermarket within walking distance is Foodtown. The range of goods there is fine, and the prices are acceptable for what you expect to pay in a supermarket. However, they do not sell any cakes of good enough quality to be worth buying. This has driven me to the biscuit aisle, where I found these.

Ernest Adams minty choc delight cookies packet.

2010-01-13 - Biscuits - 01 - Ernest Adams minty chocolate delight cookies wrapped

Ernest Adams minty choc delight cookies packet contents.

2010-01-13 - Biscuits - 02 - Ernest Adams minty chocolate delight cookies opened

At the luxury end of the biscuit scale, they should have been great. Instead they were merely okay.

The problem is that there just are not any good quality biscuits out there. I end up feeling like anything I made at home would be better for not having the taste and texture of a generic commercial product. It also tastes like some suits in an office sat around saying "this tastes good" then having settled on a flavour, said "how can we cheapen the production."

A machine made these and it tastes like it.

Adams Bruce full fruit christmas cake

I like the idea of something I can eat with a cup of tea. That might be a biscuit, or it might be a slice of cake. Cake is of course preferable to a biscuit, and christmas cake is one of the best kinds of cake. So during the christmas season, I tried a few of the commercial christmas cakes that were available.

One of these, was the Adams Bruce full fruit christmas cake.

2009-11-23 - Christmas - 01 - Adams Bruce christmas cake

This was the least satisfying cake that I tried. The icing was fine, as anything primarily made out of sugar tends to be. However the actual cake under the icing was overly rich in a flavour that the icing was unable to make up for. Not a pleasant cake, I don't think I will be buying it again.