<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>codefork.com &#187; python</title>
	<atom:link href="http://codefork.com/blog/index.php/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://codefork.com/blog</link>
	<description>branching out</description>
	<lastBuildDate>Thu, 10 Jun 2010 00:24:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Monitoring DSL diagnostics on a ZyXEL P-600 Series modem</title>
		<link>http://codefork.com/blog/index.php/2010/01/17/monitoring-dsl-diagnostics-on-a-zyxel-p-600-series-modem/</link>
		<comments>http://codefork.com/blog/index.php/2010/01/17/monitoring-dsl-diagnostics-on-a-zyxel-p-600-series-modem/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 00:51:07 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[user interface]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/?p=135</guid>
		<description><![CDATA[The DSL at the house has been really flakey the past 3 days. The line seems to periodically drop and I also noticed that the voice line had a lot of static.
I suspected a line problem so I called Earthlink support last night to try to get it straightened out. Surprisingly, the line tested good [...]]]></description>
			<content:encoded><![CDATA[<p>The DSL at the house has been really flakey the past 3 days. The line seems to periodically drop and I also noticed that the voice line had a lot of static.</p>
<p>I suspected a line problem so I called Earthlink support last night to try to get it straightened out. Surprisingly, the line tested good up until the point where it came into the house. But the diagnostics on the DSL modem were showing low noise margin (signal-to-noise ratio) and high attenuation (degradation), so there was definitely a problem somewhere. The trouble had to be inside the house: either the DSL modem or some wiring somewhere had gone bad or both.</p>
<p>I tried changing out some cables and tweaking the way the phone and fax (my housemate runs her own business) were all hooked up into the line. That seems to have fixed the problem. The line&#8217;s been steady for almost 24 hours now. I&#8217;ve been watching the diagnostics and researching what the numbers mean, and they seem to be within acceptable-to-good ranges. So far so good.</p>
<p>It was annoying to have to load the web interface on the ZyXEL P-600 Series modem (it&#8217;s a P-660R-ELNK) and continually refresh the page to watch the diagnostics. Plus I had to remember if any of the numbers changed and by how much. So I whipped up a little python script to fetch the data from the web interface and do some logging.</p>
<p>There were some interesting peculiarities in the ZyXEL web interface. After authenticating with a password, only that computer&#8217;s IP can use the interface, apparently; requests from other hosts get locked out until a few minutes of inactivity. Also, the way the interface refreshed the diagnostics page was a bit odd: it used a form submission to set some state that would cause another page to update its contents.</p>
<p>The script output looks like this:</p>
<blockquote><p>Sun Jan 17 19:15:37 2010 noise = 16 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:16:37 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:17:38 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:18:38 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:19:38 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:20:39 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:21:39 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:22:39 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:23:39 2010 noise = 18 (good) outputPower = 11 attenuation = 31 (very good)<br />
Sun Jan 17 19:24:39 2010 noise = 17 (good) outputPower = 11 attenuation = 31 (very good)</p></blockquote>
<p><a href="http://codefork.com/code/dsl_diagnostics.py">A copy of the script is available here.</a> You may need to do some tweaking to get it to work with your setup. It works with python 2.5 and 2.6.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2010/01/17/monitoring-dsl-diagnostics-on-a-zyxel-p-600-series-modem/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>FixedGearGallery Index 2.0</title>
		<link>http://codefork.com/blog/index.php/2009/05/04/fixedgeargallery-index-20/</link>
		<comments>http://codefork.com/blog/index.php/2009/05/04/fixedgeargallery-index-20/#comments</comments>
		<pubDate>Tue, 05 May 2009 05:05:36 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[culture]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[user interface]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/?p=94</guid>
		<description><![CDATA[I created a new interface for my FixedGearGallery Index. What better way to procrastinate than spending a few hours on code?
The original purpose of the index was to provide an easy way to browse through the relevant pages of a particular make/model on FGG. My first version accomplished that goal, but it&#8217;s awfully clunky. After [...]]]></description>
			<content:encoded><![CDATA[<p>I created <a href="http://codefork.com/fgg2/">a new interface for my FixedGearGallery Index</a>. What better way to procrastinate than spending a few hours on code?</p>
<p>The original purpose of the index was to provide an easy way to browse through the relevant pages of a particular make/model on FGG. My <a href="http://codefork.com/fgg/">first version</a> accomplished that goal, but it&#8217;s awfully clunky. After using it a while, I discovered how annoying it was to toggle between windows and keep track of where I was in the list.</p>
<p>The new version places navigation controls in a small area at the top of the page. It loads content from FGG into an iframe, eliminating the need for switching among windows. And the previous/next links allow you to browse sequentially, making it much easier to keep track of what you&#8217;ve already seen.</p>
<p>It&#8217;s not perfect but it&#8217;s definitely an improvement. I have fancier ideas for organizing FGG content but I don&#8217;t want to go too far by pirating Dennis&#8217; site. I&#8217;m grateful he gave me permission to do the index at all when I emailed him about it a few months ago.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2009/05/04/fixedgeargallery-index-20/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Lifespan of Software</title>
		<link>http://codefork.com/blog/index.php/2008/01/25/the-lifespan-of-software/</link>
		<comments>http://codefork.com/blog/index.php/2008/01/25/the-lifespan-of-software/#comments</comments>
		<pubDate>Fri, 25 Jan 2008 08:31:05 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2008/01/25/the-lifespan-of-software/</guid>
		<description><![CDATA[Rumors of Chandler&#8217;s Death Are Greatly Exaggerated. So says the renowned Phillip J. Eby.
In light of all the damning media scrutiny paid to Chandler in recent years, Phillip makes an excellent point: the project funded work on a bunch of important open source python libraries. I didn&#8217;t realize this&#8212;it drastically changed my regard for the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dirtsimple.org/2008/01/rumors-of-chandler-death-are-greatly.html">Rumors of Chandler&#8217;s Death Are Greatly Exaggerated</a>. So says the renowned Phillip J. Eby.</p>
<p>In light of all the damning media scrutiny paid to Chandler in recent years, Phillip makes an excellent point: the project funded work on a bunch of important open source python libraries. I didn&#8217;t realize this&mdash;it drastically changed my regard for the <a href="http://www.osafoundation.org/">OSAF</a>&#8217;s work. If this aspect of the project got mentioned more, I think Chandler would get a lot more respect. Even if Chandler 1.0 never sees the light of day, it&#8217;s already made major contributions to the python community.</p>
<p>Proprietary software has a definite lifespan: once a company has stopped developing and supporting it, that&#8217;s the end. For the company, value is localized and non-transferable in the closed source code base. The business model of selling software depends on this. Once the company kills off the product, the value more or less disappears. You can still use it, of course, but it will decrease in value as similar, hopefully better products appear on the market.</p>
<p>The value of open source software, on the other hand, isn&#8217;t limited to its immediate use. Even if an application is no longer actively used and maintained, the code can spark ideas, be used to fork a new project, serve as a lesson in design, etc. Its value can be perpetually renewed by virtue of the fact that it circulates in different ways. If it&#8217;s large enough, like Chandler or Zope, it can spawn mini-projects, components, and libraries for reuse.</p>
<p>Years ago, I wrote a Java version of a napster server. Just for fun. It was called jnerve, and I released the code as open source.  I tried to get people to host it and use it, but opennap, the C implementation, was naturally faster, more efficient, and more mature. jnerve seemed like a dead end, so I stopped working on it. There were some cool architectural bits to it that were interesting to write, but I regarded the project as a failure. </p>
<p>Months later at a conference, I got a demo CD of some new peer-to-peer file sharing software. (&#8221;P2P&#8221; was all the rage then.) When I ran it, I was astounded to see a copyright message with my name on it. They had used my code as the basis for their commercial product! The code was able to live on in a different form. I&#8217;m not sure it was actually legal, given that jnerve was GPL, but I didn&#8217;t care enough to pursue the matter.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2008/01/25/the-lifespan-of-software/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maintainability Pitfalls in PHP</title>
		<link>http://codefork.com/blog/index.php/2008/01/08/maintainability-pitfalls-in-php/</link>
		<comments>http://codefork.com/blog/index.php/2008/01/08/maintainability-pitfalls-in-php/#comments</comments>
		<pubDate>Wed, 09 Jan 2008 03:54:41 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2008/01/08/maintainability-pitfalls-in-php/</guid>
		<description><![CDATA[Tim Bray makes this prediction about PHP for 2008:
PHP will remain popular but its growth will slow, as people get nervous about its maintainability and security stories.
I share Tim&#8217;s love/hate relationship with PHP. It&#8217;s definitely a powerful and easy language. But,
&#8230; speaking as an actual computer programmer, I really dislike PHP. I find it ugly [...]]]></description>
			<content:encoded><![CDATA[<p>Tim Bray makes this <a href="http://www.tbray.org/ongoing/When/200x/2008/01/04/Predictions-PHP">prediction</a> about PHP for 2008:</p>
<blockquote><p>PHP will remain popular but its growth will slow, as people get nervous about its maintainability and security stories.</p></blockquote>
<p>I share Tim&#8217;s love/hate relationship with PHP. It&#8217;s definitely a powerful and easy language. But,</p>
<blockquote><p>&#8230; speaking as an actual computer programmer, I really dislike PHP. I find it ugly and un-modular and there’s something about it that encourages people to write horrible code. We’re talking serious maintainability pain.</p></blockquote>
<p>I&#8217;m seeing this right now in some code I&#8217;ve recently taken over. The previous programmer was quite skilled and did a great job, but it&#8217;s clear there are some areas he had to write quickly and hack together. The flip side of PHP&#8217;s ease of use is that  sloppiness accumulates very quickly when you&#8217;re doing things in a hurry. To some extent, that&#8217;s an unavoidable aspect of a growing codebase. But there&#8217;s also specific things about PHP itself that foster disorganization and unmaintainability:</p>
<p>* The lack of namespaces. This makes it hard to quickly locate a function or class definition. Classes can be used as namespaces, but that&#8217;s a hack, and leads to ugly un-OOPish uses of classes. PHP could really benefit from packages or modules.</p>
<p>* While PHP5 has vastly improved its object functionality, it often feels like the developer culture remains mired in a function-oriented paradigm. PHP&#8217;s relative ease of use and wide availability on commodity webhosting has produced a huge pool of developers whose skills are pretty wide-ranging. The low end of that tends towards hacky, function-oriented code that simply &#8220;gets the job done.&#8221; I&#8217;d like to see more thoughtful discussion on PHP sites and forums about object design and philosophy, about when to use functions and classes, and about how to mix them up harmoniously.</p>
<p>* Having a library of thousands of built-in functions in a global namespace with little rhyme or reason to their naming doesn&#8217;t exactly provide a great model of maintainability.</p>
<p>* extract() should die. Die, die, die.</p>
<p>* There&#8217;s not much agreement about OOP performance: some insist that heavy usage of some OOP features slows PHP down a lot, so you should avoid them whenever possible. Which not only is plain dumb but leads to deliberately confusing and half-assed uses of OOP in the name of better performance.</p>
<p>Maintainability is a matter of discipline, since you can write sloppy code in any language. That aside, PHP does make it extra hard to keep things orderly. I think <a href="http://www.cakephp.org/">CakePHP</a> is a step in the right direction, though if you&#8217;re going to use a strict MVC architecture, you might as well dump PHP and just go with Ruby on Rails or Python.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2008/01/08/maintainability-pitfalls-in-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Amateur thoughts and ambitions</title>
		<link>http://codefork.com/blog/index.php/2007/12/31/amateur-thoughts-and-ambitions/</link>
		<comments>http://codefork.com/blog/index.php/2007/12/31/amateur-thoughts-and-ambitions/#comments</comments>
		<pubDate>Tue, 01 Jan 2008 00:32:12 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/12/31/amateur-thoughts-and-ambitions/</guid>
		<description><![CDATA[One of the better things I&#8217;ve stumbled across this past year is Larry Lessig&#8217;s talk, How creativity is being strangled by the law. 
The piece makes his usual argument that copyright law stifles innovation in the age of new media. Most striking to me, though, was the part where he uses the phrase &#8220;amateur culture.&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>One of the better things I&#8217;ve stumbled across this past year is Larry Lessig&#8217;s talk, <a href="http://www.ted.com/talks/view/id/187">How creativity is being strangled by the law</a>. </p>
<p>The piece makes his usual argument that copyright law stifles innovation in the age of new media. Most striking to me, though, was the part where he uses the phrase &#8220;amateur culture.&#8221; He explains, &#8220;&#8230;I don&#8217;t mean amateurish culture, I mean culture where people produce for the love of what they&#8217;re doing and not for the money.&#8221; He uses the term to describe the activity of &#8220;kids&#8221; (?) creating their own remixes from existing media.</p>
<p>I can remember another amateur culture that&#8217;s now largely disappeared. Back in my teens, modem-based bulletin board systems (BBSes) fostered a rich &#8220;read-write&#8221; culture for amateur programmers. Most of us did not work in technology; after all, the commercial Internet hadn&#8217;t been born yet, so the computing industry was much smaller and more obscure. A career as a programmer seemed like a mysterious and rarefied thing to me back then. The coders you met on BBSes were often people who simply liked to do programming in their spare time.</p>
<p>These systems allowed us to circulate public domain source code for fun games and useful applications written in BASIC, Pascal, C, even assembler. We hacked on existing code to get it to do what we wanted, trying to figure out ways to push the limits of our little 8086 processors and 640K of RAM. We mingled regardless of our level of knowledge, beginners and experts alike. We had friendly user meetings in diners in Brooklyn and Manhattan (I lived in NY at the time), where we chatted about home-grown upgrades and discussed how to link up to the nation-wide discussion networks that existed then.</p>
<p>It was amateur culture at its best: lots of exchange, circulation, and cooperation happened all the time. But it was definitely not amateurish. Many were extremely capable and knowledgeable coders.</p>
<p>Today, there are still people who code just because they enjoy it, but the amateur culture and its community hardly exist anymore. Beginners on web forums are more interested in what they need to know in order to land a job, rather than in coding itself. Even open source projects tend to be dominated by career professionals; read any public mailing list and you&#8217;ll see how unhelpful they often are to amateurs who want to get involved. One reason I like python is that the project makes a genuine effort to connect to the sensibilities of amateurs. But even its forums are littered with snarky individuals.</p>
<p>All of this is largely due, I think, to the ideology of professionalism, which convinces us that having a stable career is the pinnacle of achievement. It damagingly equates amateurs with dilettantes. That&#8217;s why one of the first things we ask in this country when meeting a stranger is, &#8220;So what do you do?&#8221; By which we really mean, &#8220;Tell me what you do for a living so I can know who you are and whether you&#8217;re worth talking to.&#8221;</p>
<p>In 2008, I resolve to be more wary of this ideology and its negative effects. I want to embrace being an amateur in the various things that I do. I want to think less about careers and focus more on how to best spend my time doing what&#8217;s important to me. And I want to find more amateurs to hang out with as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/12/31/amateur-thoughts-and-ambitions/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pimping Python&#8217;s property()</title>
		<link>http://codefork.com/blog/index.php/2007/12/05/pimping-pythons-property/</link>
		<comments>http://codefork.com/blog/index.php/2007/12/05/pimping-pythons-property/#comments</comments>
		<pubDate>Wed, 05 Dec 2007 17:57:55 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/12/05/pimping-pythons-property/</guid>
		<description><![CDATA[A basic tenet of object oriented coding is encapsulation: expose the interface but hide the implementation.
Seductress that it is, Python makes it very tempting to violate this principle. Since all members of an object are public, it&#8217;s easy to access and modify them from outside. For example:
class Person:
    def __init__(self):
   [...]]]></description>
			<content:encoded><![CDATA[<p>A basic tenet of object oriented coding is <a href="http://en.wikipedia.org/wiki/Object-oriented_programming#Fundamental_concepts">encapsulation</a>: expose the interface but hide the implementation.</p>
<p>Seductress that it is, Python makes it very tempting to violate this principle. Since all members of an object are public, it&#8217;s easy to access and modify them from outside. For example:</p>
<pre>class Person:
    def __init__(self):
        self.age = None
jeff = Person()
jeff.age = 5 # maturity</pre>
<p>Compare this with Java, where you can make a member private, and use &#8220;getters&#8221; and &#8220;setters&#8221;:</p>
<pre>class Person {
    private int age;
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public static void main(String[] args) {
        Person jeff = new Person();
        jeff.setAge(5);
    }
}</pre>
<p>The Java version has better encapsulation. If you decide later to change &#8220;age&#8221; to, say, a float, a string(!), or if you move it into another internally linked object, it&#8217;s no big deal. Just change the body of the getAge() and setAge() methods to do the typecasting or make the extra call, and you won&#8217;t need to change any other code. The implementation changes; the interface stays the same.</p>
<p>Of course, you could write getters and setters in Python, too, but you can&#8217;t enforce their use (data members are public, remember?). A better way is to do some magic using __getattr__ and __setattr__, although that could get messy, especially if you have a lot of names to intercept.</p>
<p>This has been bothering me for a while. Then I recently discovered the built-in function property(), which lets you rewrite the example above as follows:</p>
<pre>class Person(object):
    def __init__(self):
        self._age = None
    def get_age(self):
        return self._age
    def set_age(self, value):
        self._age = value
    def del_age(self):
        del self._age
    age = property(get_age, set_age, del_age)
jeff = Person()
jeff.age = 5</pre>
<p>Sweeeet. From the outside, nothing seems different: it still appears that you&#8217;re getting and setting age directly, just as before. But property() calls get_age and set_age transparently, giving you a layer that effectively provides encapsulation, even though you can&#8217;t tell from the outside. After all, that&#8217;s the whole point of encapsulation: you <em>shouldn&#8217;t</em> be able to tell from the outside. </p>
<p>In fact, this is actually better than how Java does it. A first version of Person might very well have age as a member which its users directly modify: this is intuitive and effortless, both conceptually and syntactically. Only later might you need to bring property() into the picture, as the object&#8217;s internals change or grow more complex. And that&#8217;s how it should be: more lines of code and more complexity <em>only</em> when you need it.</p>
<p>(Of course, you still can&#8217;t hide data members, but this still goes a long way towards better, though not complete, encapsulation.)</p>
<p>I can&#8217;t remember ever seeing property() mentioned anywhere in tutorials or introductory docs (it&#8217;s in the <a href="http://docs.python.org/lib/built-in-funcs.html">reference for built-in functions</a>) That&#8217;s especially odd considering that one of Python&#8217;s strengths is its powerful object features. It would make sense to talk about this in the context of encapsulation. Plus I wonder how widespread the use of property() is in real world code.</p>
<p>Stuff like this is why I love Python.</p>
<p><strong>Update</strong>: Some good comments over at <a href="http://programming.reddit.com/info/62ae7/comments/">reddit</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/12/05/pimping-pythons-property/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Mashup: Google Maps + Amazon Reviews</title>
		<link>http://codefork.com/blog/index.php/2007/11/14/mashup-google-maps-amazon-reviews/</link>
		<comments>http://codefork.com/blog/index.php/2007/11/14/mashup-google-maps-amazon-reviews/#comments</comments>
		<pubDate>Wed, 14 Nov 2007 07:55:43 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[ajax]]></category>
		<category><![CDATA[misc]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/11/14/mashup-google-maps-amazon-reviews/</guid>
		<description><![CDATA[Saturday morning I woke up with a rather odd idea: to create a mashup of google maps and Amazon book reviews. I was mildly surprised to discover it hadn&#8217;t been done yet. Here&#8217;s the result of spending a chunk of the weekend writing it in python (11/15 Update: should now work in Safari, Firefox2, and [...]]]></description>
			<content:encoded><![CDATA[<p>Saturday morning I woke up with a rather odd idea: to create a mashup of google maps and Amazon book reviews. I was mildly surprised to discover it hadn&#8217;t been done yet. Here&#8217;s the result of spending a chunk of the weekend writing it in python (<strong>11/15 Update</strong>: should now work in Safari, Firefox2, and IE6):</p>
<p><a href="http://mapreviews.codefork.com">http://mapreviews.codefork.com</a></p>
<p>It didn&#8217;t take long to write, since I&#8217;d recently been investigating the google maps API for a friend, and I&#8217;d also been doing bits of Amazon integration for a project. The biggest pain was dealing with the 1 call per second per IP address rate limiting mechanism of Amazon&#8217;s ECS API: the service returns error codes if you exceed the limit. So the application is pretty slow, especially if others are also using it. </p>
<p>But if you&#8217;re patient, it&#8217;s fun to watch the map markers gradually pop up. It&#8217;s also fun to look up a book with strong political leanings, and see how the ratings are distributed geographically. For example, you can look at <a href="http://mapreviews.codefork.com/index.html?0140447571">The Communist Manifesto</a> by Marx, and Bill O&#8217;Reilly&#8217;s <a href="http://mapreviews.codefork.com/index.html?0767920937">Culture Warrior</a> (*shudder*). Data for both are cached, so they should load very fast.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/11/14/mashup-google-maps-amazon-reviews/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Small Victories</title>
		<link>http://codefork.com/blog/index.php/2007/11/04/small-victories/</link>
		<comments>http://codefork.com/blog/index.php/2007/11/04/small-victories/#comments</comments>
		<pubDate>Sun, 04 Nov 2007 23:23:34 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/11/04/small-victories/</guid>
		<description><![CDATA[It always feels very rewarding when my coding-related problems have happy outcomes. A few small but cool things that have happened recently:
A while ago, I discovered an issue with the way the cherrypy web server resolves &#8220;localhost&#8221; to an IP6 address on some operating systems. The cherrypy folks actually listened to my suggestion and made [...]]]></description>
			<content:encoded><![CDATA[<p>It always feels very rewarding when my coding-related problems have happy outcomes. A few small but cool things that have happened recently:</p>
<p>A while ago, I discovered an issue with the way the cherrypy web server resolves &#8220;localhost&#8221; to an IP6 address on some operating systems. The cherrypy folks <a href="http://groups.google.com/group/cherrypy-users/browse_thread/thread/a71e2c29ac8cbad3/">actually listened to my suggestion</a> and made a helpful change.</p>
<p>It looks like <a href="http://code.google.com/p/feedparser/issues/detail?id=18">one person has already benefited</a> from the tiny patch I created for a feedparser issue last week.</p>
<p>When I couldn&#8217;t get SQLAlchemy&#8217;s &#8220;pool_recycle&#8221; option to properly close and re-open inactive connections, the estimable Michael Bayer took a minute out of his busy life to <a href="http://groups.google.com/group/sqlalchemy/browse_thread/thread/a6564a9a95ec1d8e/">explain what I had missed</a>, for which I was extremely grateful. (One of these days, I need to write about a post about how truly amazing SQLAlchemy is.)</p>
<p>Open source projects create the opportunities for good things to happen. Most of the time. (Or maybe it&#8217;s just the python projects.)</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/11/04/small-victories/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>In praise of feedparser</title>
		<link>http://codefork.com/blog/index.php/2007/10/28/in-praise-of-feedparser/</link>
		<comments>http://codefork.com/blog/index.php/2007/10/28/in-praise-of-feedparser/#comments</comments>
		<pubDate>Mon, 29 Oct 2007 06:41:03 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/10/28/in-praise-of-feedparser/</guid>
		<description><![CDATA[I discovered an issue this morning in the excellent feedparser module.
feedparser (aka Universal Feed Parser) has a reputation in the python community for being an incredible piece of code. With good reason: it understands a mind-boggling array of feed formats and versions, and it&#8217;s been put through the paces with a suite of 3262 unit [...]]]></description>
			<content:encoded><![CDATA[<p>I discovered an issue this morning in the excellent <a href="http://feedparser.org/">feedparser</a> module.</p>
<p>feedparser (aka Universal Feed Parser) has a reputation in the python community for being an incredible piece of code. With good reason: it understands a mind-boggling array of feed formats and versions, and it&#8217;s been put through the paces with a suite of 3262 unit tests. Mark Pilgrim&#8217;s terrific work has saved me (and many others, no doubt) months of toil and sweat.</p>
<p>The issue has to do with encountering multiple &#8220;title&#8221; tags defined in different XML namespaces. A dc:title or media:title tag, if it is encountered anywhere after a regular RSS title tag, will overwrite it. Several other people have actually already documented this in the bug tracking system.</p>
<p>It&#8217;s unclear how much work is actively being done with feedparser these days, so I reluctantly dived into the module to try to see what was going on. A little over an hour later, with almost no pain, I found myself with a patch that passed the test suite. I&#8217;d love to say it was due to my incredible coding prowess, but really, the code is just amazingly clean and easy to understand. That&#8217;s how fixing bugs should be.</p>
<p>The patch is <a href="http://code.google.com/p/feedparser/issues/detail?id=18">here</a> if anyone wants it.</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/10/28/in-praise-of-feedparser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Uses of Function Attributes</title>
		<link>http://codefork.com/blog/index.php/2007/10/15/the-uses-of-function-attributes/</link>
		<comments>http://codefork.com/blog/index.php/2007/10/15/the-uses-of-function-attributes/#comments</comments>
		<pubDate>Mon, 15 Oct 2007 17:56:40 +0000</pubDate>
		<dc:creator>jeff</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://codefork.com/blog/index.php/2007/10/15/the-uses-of-function-attributes/</guid>
		<description><![CDATA[A Python function is an object of type &#8220;function.&#8221; One of the things you can do, as a result, is set attributes on the function object, like so:
def say_hello():
	print "hi!"
say_hello.x = 1
(You can also do that on a function that&#8217;s an object method.)
This is pretty odd. In some ways, this feature interestingly blurs the distinction [...]]]></description>
			<content:encoded><![CDATA[<p>A Python function is an object of type &#8220;function.&#8221; One of the things you can do, as a result, is set attributes on the function object, like so:</p>
<pre>def say_hello():
	print "hi!"
say_hello.x = 1</pre>
<p>(You can also do that on a function that&#8217;s an object method.)</p>
<p>This is pretty odd. In some ways, this feature interestingly blurs the distinction among classes, objects, and functions, since all of them can have their own attributes. It strikes me that this illustrates one of the key philosophical differences between Python and a language like Java, where object-oriented principles are more rigidly enforced, In Java, a class is a class, an object is an object, and a method is a method. We shall not even speak of functions!</p>
<p>For a while, I understood this language feature, but not its real utility, which is this: you don&#8217;t have to write entire classes for small pieces of functionality.</p>
<p><a href="http://www.cherrypy.org">cherrypy</a> is a good example. It uses the attribute name &#8220;exposed&#8221; to indicate whether a method should be accessible to the URL-to-object mapping mechanism. Combined with some other clever design, this allows an HTTP request handler to be an ordinary method in a tree structure that corresponds to the web application&#8217;s URL scheme. By contrast, in Java, you have to subclass Servlet for each handler, and then manually map those Servlets to URLs. Ugh.</p>
<p>Another use is that decorators can manipulate the attributes of functions they modify. If the decorator&#8217;s behavior should change based on state, or it wants to track statistics or debugging information, it can use the underlying function&#8217;s attributes for storage. (Some examples of this are strewn throughout the <a href="http://wiki.python.org/moin/PythonDecoratorLibrary">PythonDecoratorLibrary</a> page at the Python Wiki.) Again, this avoids extra class definitions and objects, which would typically be necessary for separately storing that state information.</p>
<p>The last use I can think of right now is that you can easily and quickly create singletons. Because classes are meant for instantiation into objects, it can be inelegant to enforce a singleton pattern. With function attributes, you can define a function in a module, set some defaults, and allow callers to manipulate them, which will remain a single set application-wide. </p>
<p>(Note that you CAN create multiple instances of a function, as <a href="http://paddy3118.blogspot.com/2006/05/python-function-attributes.html">this interesting example</a> shows. But the singleton idea is still sound in the context of module functions.)</p>
]]></content:encoded>
			<wfw:commentRss>http://codefork.com/blog/index.php/2007/10/15/the-uses-of-function-attributes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
