<?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>LuckyDonkey &#187; Python</title>
	<atom:link href="http://www.luckydonkey.com/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.luckydonkey.com</link>
	<description>Never knowingly knowing narwhals</description>
	<lastBuildDate>Wed, 17 Mar 2010 01:05:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Beep My Stuff enters public Beta</title>
		<link>http://www.luckydonkey.com/2009/04/02/beep-my-stuff-enters-public-beta/</link>
		<comments>http://www.luckydonkey.com/2009/04/02/beep-my-stuff-enters-public-beta/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 23:00:23 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[Beep My Stuff]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[SQLAlchemy]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/?p=226</guid>
		<description><![CDATA[After a rather long period in closed beta I've opened Beep My Stuff to a public beta. Beep My Stuff is a web site that makes it FREE and easy to create an online library of your Books, Movies, Video Games and Music. Check it out, all feedback is much appreciated. It's built with Turbogears, [...]]]></description>
			<content:encoded><![CDATA[<p><div id="attachment_232" class="wp-caption aligncenter" style="width: 310px"><img src="http://www.luckydonkey.com/wp-content/uploads/2009/04/bms_logo-300x147.jpg" alt="Beep My Stuff" title="bms_logo" width="300" height="147" class="size-medium wp-image-232" /><p class="wp-caption-text">Beep My Stuff</p></div><br />
After a rather long period in closed beta I've opened <a href="http://www.beepmystuff.com/">Beep My Stuff</a> to a public beta.</p>
<p><a href="http://www.beepmystuff.com/">Beep My Stuff</a> is a web site that makes it FREE and easy to create an online library of your Books, Movies, Video Games and Music. Check it out, all feedback is much appreciated.</p>
<p>It's built with <a href="http://www.turbogears.org/">Turbogears</a>, <a href="http://www.sqlalchemy.org/">SQLAlchemy</a>, <a href="http://genshi.edgewall.org/">Genshi</a> and countless other python modules. It's all sitting on <a href="http://www.python.org/">Python</a>, <a href="http://www.freebsd.org/">FreeBSD</a> and <a href="http://www.postgresql.org/">PostgreSQL</a>.</p>
<p>Just wanted to say thanks to all the pythonista's out there that helped me get this far <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><map name='google_ad_map_226_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/226?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_226_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=226&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2009%2F04%2F02%2Fbeep-my-stuff-enters-public-beta%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2009/04/02/beep-my-stuff-enters-public-beta/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mutlipart file upload in Turbogears 1.0.x</title>
		<link>http://www.luckydonkey.com/2009/03/16/mutlipart-file-upload-in-turbogears-10x/</link>
		<comments>http://www.luckydonkey.com/2009/03/16/mutlipart-file-upload-in-turbogears-10x/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 15:27:58 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[Beep My Stuff]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/2009/03/16/mutlipart-file-upload-in-turbogears-10x/</guid>
		<description><![CDATA[When uploading files to Beep My Stuff using SWFUpload I was getting this error: data = self._sock.recv&#40;self._rbufsize&#41; timeout: timed out Uploading files to a TG1.0.x app is easy unless you want to do something nice like use SWFUpload to allow multiple files to be selected for upload. The reason for this is that Flash has [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
//468x60, created 11/22/07
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>When uploading files to <a href='http://www.beepmystuff.com'>Beep My Stuff</a> using <a href="http://swfupload.org/">SWFUpload</a> I was getting this error:</p>
<pre class="python">data = <span style="color: #008000;">self</span>._sock.<span style="color: black;">recv</span><span style="color: black;">&#40;</span><span style="color: #008000;">self</span>._rbufsize<span style="color: black;">&#41;</span>
timeout: timed out</pre>
<p>Uploading files to a TG1.0.x app is easy unless you want to do something nice like use <a href="http://swfupload.org/">SWFUpload</a> to allow multiple files to be selected for upload.</p>
<p>The reason for this is that Flash has interpreted <a href="http://www.ietf.org/rfc/rfc2046.txt">RFC 2046</a> one way and they python libraries/CherryPy interpret it another. Fortunately this is fixed in Turbogears 1.1+ but I am using 1.08 at the moment for <a href='http://www.beepmystuff.com'>Beep My Stuff</a> so I needed a fix.</p>
<p>There is a <a href="http://www.cherrypy.org/attachment/ticket/648/flash8.patch">patch</a> in CherryPy that can be used to fix the problem and Chris Arndt has created a patch for TG1.1. You can easily apply the same code to your TG1.0x app to fix this problem as well.</p>
<p>Visit <a href="http://trac.turbogears.org/attachment/ticket/1953/safemultipart-filter.diff">here</a> and copy the contents of safemutlipart.py into a file in your project. Then you need to install the filter when <a href="http://www.turbogears.org/">Turbogears</a> is starting up. Something like this will do the trick:</p>
<pre class="python"><span style="color: #808080; font-style: italic;">#force the multipart filter to be installed.</span>
<span style="color: #ff7700;font-weight:bold;">def</span> install_safemutlipartfilter<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">from</span> cherrypy <span style="color: #ff7700;font-weight:bold;">import</span> root
    root._cp_filters.<span style="color: black;">extend</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>SafeMultipartFilter<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> install_multipart_filter<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">from</span> turbogears.<span style="color: black;">startup</span> <span style="color: #ff7700;font-weight:bold;">import</span> call_on_startup
    log.<span style="color: black;">info</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Installing multipart filter&quot;</span><span style="color: black;">&#41;</span>
    call_on_startup.<span style="color: black;">append</span><span style="color: black;">&#40;</span>install_safemutlipartfilter<span style="color: black;">&#41;</span></pre>
<p>Note that the code in SafeMultiPartFilter needs a config change to turn it on so add</p>
<pre>safempfilter.on = True</pre>
<p>to your app.cfg</p>
<p>hope that helps <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><map name='google_ad_map_215_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/215?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_215_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=215&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2009%2F03%2F16%2Fmutlipart-file-upload-in-turbogears-10x%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2009/03/16/mutlipart-file-upload-in-turbogears-10x/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Replaying apache log files with python and twill</title>
		<link>http://www.luckydonkey.com/2008/10/02/replaying-apache-log-files-with-python-and-twill/</link>
		<comments>http://www.luckydonkey.com/2008/10/02/replaying-apache-log-files-with-python-and-twill/#comments</comments>
		<pubDate>Thu, 02 Oct 2008 00:06:19 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[NewMetalArmy]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/?p=211</guid>
		<description><![CDATA[In order to test for a memory leak in New Metal Army I needed to replay my apache log files against my test server. Using Twill this was a doddle. The only slightly icky thing about the script is the regular expression to parse a line from the apache log file (in Combined Log Format). [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
//468x60, created 11/22/07
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>In order to test for a memory leak in <a href="http://www.newmetalarmy.com">New Metal Army</a> I needed to replay my apache log files against my test server. Using <a href='http://twill.idyll.org/'>Twill</a> this was a doddle.</p>
<p>The only slightly icky thing about the script is the regular expression to parse a line from the apache log file (in <a href="http://httpd.apache.org/docs/2.2/logs.html">Combined Log Format</a>). I got this from <a href="http://www.regexbuddy.com/">RegExp Buddy</a> (pretty much the only reason I run Windows nowadays) but I am sure you can get similar expressions from other <a href="http://www.google.co.uk/search?q=regular+expression+libraries">regular expression libraries</a>.</p>
<p>Anyway, I'm just chucking this out there incase someone else finds it useful.</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">re</span>
<span style="color: #ff7700;font-weight:bold;">import</span> twill
&nbsp;
test_server=<span style="color: #483d8b;">&quot;my.test.server.com&quot;</span>
&nbsp;
reobj = <span style="color: #dc143c;">re</span>.<span style="color: #008000;">compile</span><span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^(?P&lt;client&gt;<span style="color: #000099; font-weight: bold;">\S</span>+)<span style="color: #000099; font-weight: bold;">\s</span>+(?P&lt;auth&gt;<span style="color: #000099; font-weight: bold;">\S</span>+<span style="color: #000099; font-weight: bold;">\s</span>+<span style="color: #000099; font-weight: bold;">\S</span>+)<span style="color: #000099; font-weight: bold;">\s</span>+<span style="color: #000099; font-weight: bold;">\[</span>(?P&lt;datetime&gt;[^]]+)<span style="color: #000099; font-weight: bold;">\]</span><span style="color: #000099; font-weight: bold;">\s</span>+&quot;(?:GET|POST|HEAD) (?P&lt;file&gt;[^ ?&quot;]+)<span style="color: #000099; font-weight: bold;">\?</span>?(?P
&lt;parameters&gt;[^ ?&quot;]+)? HTTP/[0-9.]+&quot;<span style="color: #000099; font-weight: bold;">\s</span>+(?P&lt;status&gt;[0-9]+)<span style="color: #000099; font-weight: bold;">\s</span>+(?P&lt;size&gt;[-0-9]+)<span style="color: #000099; font-weight: bold;">\s</span>+&quot;(?P&lt;referrer&gt;[^&quot;]*)&quot;<span style="color: #000099; font-weight: bold;">\s</span>+&quot;(?P&lt;useragent&gt;[^&quot;]*)&quot;$'</span>, <span style="color: #dc143c;">re</span>.<span style="color: black;">MULTILINE</span><span style="color: black;">&#41;</span>
browser = twill.<span style="color: black;">get_browser</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> filter_url<span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #008000;">False</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">for</span> line <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">open</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;apache.log&quot;</span><span style="color: black;">&#41;</span>:
    match = reobj.<span style="color: black;">search</span><span style="color: black;">&#40;</span>line<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">if</span> match <span style="color: #ff7700;font-weight:bold;">is</span> <span style="color: #008000;">None</span>:
        <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
    f = match.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;file&quot;</span><span style="color: black;">&#41;</span>
    p = match.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;parameters&quot;</span><span style="color: black;">&#41;</span>
    d = match.<span style="color: black;">group</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;datetime&quot;</span><span style="color: black;">&#41;</span>
    path = <span style="color: #483d8b;">&quot;?&quot;</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>f, p<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">if</span> p <span style="color: #ff7700;font-weight:bold;">else</span> f
&nbsp;
    url = test_server+path
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">if</span><span style="color: black;">&#40;</span>filter_url<span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">try</span>:
        <span style="color: #ff7700;font-weight:bold;">print</span> d, url
        browser.<span style="color: black;">go</span><span style="color: black;">&#40;</span>url<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ValueError</span>:
        <span style="color: #808080; font-style: italic;">#this comes from twill parsing the HTML and it being malformed.</span>
        <span style="color: #808080; font-style: italic;">#I don't really care about that, as long as I get the page.</span>
        <span style="color: #ff7700;font-weight:bold;">pass</span>
&nbsp;</pre>
<p><map name='google_ad_map_211_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/211?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_211_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=211&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F10%2F02%2Freplaying-apache-log-files-with-python-and-twill%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/10/02/replaying-apache-log-files-with-python-and-twill/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQLAlchemy-Migrate upgrade scripts in a transaction</title>
		<link>http://www.luckydonkey.com/2008/07/27/sqlalchemy-migrate-upgrade-scripts-in-a-transaction/</link>
		<comments>http://www.luckydonkey.com/2008/07/27/sqlalchemy-migrate-upgrade-scripts-in-a-transaction/#comments</comments>
		<pubDate>Sun, 27 Jul 2008 23:51:50 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[NewMetalArmy]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[SQLAlchemy]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/?p=210</guid>
		<description><![CDATA[SQLAlchemy Migrate is a really good tool for managing database upgrades for SQLAlchemy centric projects. I've been using it for 6 months on New Metal Army and I haven't had a screwed website upgrade yet! For those that don't know SQLAlchemy-migrate allows you to version control database changes and easily upgrade and downgrade a database. [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<br clear="all"><a href="http://code.google.com/p/sqlalchemy-migrate/">SQLAlchemy Migrate</a> is a really good tool for managing database upgrades for <a href="http://www.sqlalchemy.org/">SQLAlchemy</a> centric projects. I've been using it for 6 months on <a href="http://www.newmetalarmy.com">New Metal Army</a> and I haven't had a screwed website upgrade yet!</p>
<p>For those that don't know SQLAlchemy-migrate allows you to version control database changes and easily upgrade and downgrade a database. Basically you write a python script with two functions: upgrade and downgrade. You test the script against the database, commit it to the SQLAlchemy-migrate version repository (not to be confused with your source control mechanism). Finally you upgrade your development database.</p>
<p>When it the time comes to deploy the new application you simply ask sqlalchemy-migrate to upgrade your database to the current version. sqlalchemy-migrate reads the current version of your schema from the database (via a custom table it inserts) and proceeds to upgrade your schema by running each upgrade script in turn.</p>
<p>Often you want your upgrades and downgrades to run within a transaction. Not because you expect them to fail but because while writing them you don't wont to leave the database partially upgraded or downgraded if your script fails. To do this I wrote a transaction decorator. Here is a template for an upgrade script:</p>
<pre class="python"><ol><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #808080; font-style: italic;">#!/usr/bin/env python</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #808080; font-style: italic;"># encoding: utf-8</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">from</span> <span style="color: #dc143c;">datetime</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">datetime</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">from</span> sqlalchemy <span style="color: #ff7700;font-weight:bold;">import</span> *</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">from</span> migrate <span style="color: #ff7700;font-weight:bold;">import</span> *</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">from</span> migrate.<span style="color: black;">changeset</span> <span style="color: #ff7700;font-weight:bold;">import</span> *</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">metadata = MetaData<span style="color: black;">&#40;</span>migrate_engine<span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">def</span> transaction<span style="color: black;">&#40;</span>f, *args, **kwargs<span style="color: black;">&#41;</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    <span style="color: #ff7700;font-weight:bold;">def</span> wrapper<span style="color: black;">&#40;</span>*args, **kwargs<span style="color: black;">&#41;</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">        connection = migrate_engine.<span style="color: black;">connect</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">        transaction = connection.<span style="color: black;">begin</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">        <span style="color: #ff7700;font-weight:bold;">try</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            result = f<span style="color: black;">&#40;</span>*args, **kwargs<span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            transaction.<span style="color: black;">commit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            <span style="color: #ff7700;font-weight:bold;">return</span> result</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">        <span style="color: #ff7700;font-weight:bold;">except</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            transaction.<span style="color: black;">rollback</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            <span style="color: #ff7700;font-weight:bold;">raise</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">        <span style="color: #ff7700;font-weight:bold;">finally</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">            connection.<span style="color: black;">close</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    wrapper.__name__ = f.__name__</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    wrapper.<span style="color: #0000cd;">__dict__</span> = f.<span style="color: #0000cd;">__dict__</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    wrapper.__doc__ = f.__doc__</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    <span style="color: #ff7700;font-weight:bold;">return</span> wrapper</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">@transaction</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">def</span> upgrade<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    <span style="color: #ff7700;font-weight:bold;">pass</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">@transaction</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color: #ff7700;font-weight:bold;">def</span> downgrade<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:</div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">    <span style="color: #ff7700;font-weight:bold;">pass</span></div></li><li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;"><div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div></li></ol></pre>
<p>I fill in the upgrade and downgrade functions and I'm done <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>I include the decorator in every script as it's good practice to make your scripts as independent as possible. If you imported it from a module you may improve it in the future and inadvertently break your old downgrade scripts.</p>
<p>I hope this  helps you version control your database schema and data.</p>
<p><map name='google_ad_map_210_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/210?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_210_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=210&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F07%2F27%2Fsqlalchemy-migrate-upgrade-scripts-in-a-transaction%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/07/27/sqlalchemy-migrate-upgrade-scripts-in-a-transaction/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>FreeBSD 7.0: installing psycopg 2.07</title>
		<link>http://www.luckydonkey.com/2008/07/23/freebsd-70-installing-psycopg-207/</link>
		<comments>http://www.luckydonkey.com/2008/07/23/freebsd-70-installing-psycopg-207/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 17:37:35 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/?p=209</guid>
		<description><![CDATA[While setting up a new FreeBSD 7.0 server I found that psycopg 2.0.7 doesn't easy_install on FreeBSD. It's because of a configuration problem in config.h at the bottom. #if defined(__FreeBSD__) &#124;&#124; (defined(_WIN32) &#38;&#38; !defined(__GNUC__)) &#124;&#124; defined(__sun__) /* what's this, we have no round function either? */ static double round&#40;double num&#41; &#123; return &#40;num &#62;= 0&#41; [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<br clear="all">While setting up a new FreeBSD 7.0 server I found that psycopg 2.0.7 doesn't easy_install on FreeBSD. It's because of a configuration problem in config.h at the bottom.</p>
<pre class="cpp"><span style="color: #339900;">#if defined(__FreeBSD__) || (defined(_WIN32) &amp;&amp; !defined(__GNUC__)) || defined(__sun__)</span>
<span style="color: #ff0000; font-style: italic;">/* what's this, we have no round function either? */</span>
<span style="color: #0000ff;">static</span> <span style="color: #0000ff;">double</span> round<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">double</span> num<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
  <span style="color: #0000ff;">return</span> <span style="color: #000000;">&#40;</span>num &gt;= <span style="color: #0000dd;">0</span><span style="color: #000000;">&#41;</span> ? <span style="color: #0000dd;">floor</span><span style="color: #000000;">&#40;</span>num + <span style="color: #0000dd;">0.5</span><span style="color: #000000;">&#41;</span> : <span style="color: #0000dd;">ceil</span><span style="color: #000000;">&#40;</span>num - <span style="color: #0000dd;">0.5</span><span style="color: #000000;">&#41;</span>;
<span style="color: #000000;">&#125;</span>
<span style="color: #339900;">#endif</span>
&nbsp;</pre>
<p>However 'round' is defined in FreeBSD and has been since FreeBSD 5.3 (according to the manual page). The fix is simple, just remove the 'defined(__FreeBSD__) ||' part of the '#if' and you should be fine. Now you can 'easy_install .' psycopg2.</p>
<p>PS: I'd tried to raise a ticket but http://www.initd.org/ trac seems to have been down for ages.</p>
<p><map name='google_ad_map_209_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/209?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_209_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=209&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F07%2F23%2Ffreebsd-70-installing-psycopg-207%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/07/23/freebsd-70-installing-psycopg-207/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Turbogears Development: Enviroment</title>
		<link>http://www.luckydonkey.com/2008/04/19/turbogears-development-enviroment/</link>
		<comments>http://www.luckydonkey.com/2008/04/19/turbogears-development-enviroment/#comments</comments>
		<pubDate>Sat, 19 Apr 2008 10:08:05 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[NewMetalArmy]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Subversion]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/?p=201</guid>
		<description><![CDATA[I thought I'd run through a list of tools that I used to make New Metal Army. New Metal Army is my first major website and I learned a lot along the way. Here are the tools in no particular order: Subversion First and foremost, subversion is a source control tool but it's also a [...]]]></description>
			<content:encoded><![CDATA[<p>I thought I'd run through a list of tools that I used to make <a href="http://www.newmetalarmy.com">New Metal Army</a>. New Metal Army is my first major website and I learned a lot along the way. Here are the tools in no particular order:</p>
<h2><a href="http://subversion.tigris.org/">Subversion</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080112.jpg" height="106" width="123" border="1" hspace="4" vspace="4" alt="200804080112" style="float:left; border:0px;" />First and foremost, subversion is a source control tool but it's also a safety net. I can't see how you can call yourself a developer if you don't have source control. From day one I got myself an account on <a href="http://www.webfaction.com/?affiliate=eunit">Webfaction</a> set up subversion and started versioning everything. They allow https connection so everything is safe and because I don't live in their data center it's off site as well <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<br clear="all"/></p>
<h2><a href="http://trac.edgewall.org/">Trac</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/trac-logo.png" height="61" width="55" border="1" hspace="4" vspace="4" alt="Trac Logo" style="float:left; border:0px" />Again on <a href="http://www.webfaction.com/?affiliate=eunit">Webfaction</a>, I installed Trac. Trac is a project management webtool. It hooks in to svn so you can see repository changes as a timeline and see checkins as colored diffs. It also has a ticket system and wiki. I found the wiki to be invaluable. It allowed me to track my thoughts in a 'low barrier to entry' fashion. It's so easy to add a wiki page, there really isn't any excuse for not doing it! The ticket/task tracking is basic but fine for small teams. There is a simple notion of a milestone and a release but the metrics for measuring progress just aren't there. For me though, this was fine. Web projects are relatively simple and single man projects don't require metrics really.<br />
<br clear="all"/></p>
<h2><a href="http://macromates.com/">TextMate</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080025.jpg" height="131" width="140" border="1" hspace="4" vspace="4" alt="200804080025" style="float:left; border:0px" />TextMate is a text editor primarily aimed at programmers but useful for anyone who needs to edit structured documents where the content is more important then the layout. I first ran in to TextMate while I was evaluating Ruby. The Ruby community seems to be dominated by macbook pro users sitting in Starbucks, bashing code in to TextMate and buzzing on coffee. Although I decided not to use Ruby I did stick with TextMate. It really is the premier text editor for OS X. It's the first editor that has replaced emacs for me. I didn't use any extensions for TextMate but I did use <a href="http://pychecker.sourceforge.net/">PyChecker</a> and <a href="http://www.jslint.com/">JSLint</a> with it to check my python and Javascript code on save.<br />
<br clear="all"/></p>
<h2><a href="http://macrabbit.com/cssedit/">CSSEdit</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080026.jpg" height="134" width="158" border="1" hspace="4" vspace="4" alt="200804080026" style="float:left; border:0px" />CSSEdit is an editor devoted to CSS. The cool thing is that it has live editting. So as you edit the CSS file for a site, it changes the preview of the site. This is quite frankly brilliant and very cheap compared to the time it saved me. <br/>Combined with <a href="http://developer.yahoo.com/yui/">YUI</a>'s <a href="http://developer.yahoo.com/yui/reset/">CSSReset</a> I can proudly say I 'ported' New Metal Army from Firefox to Safari, IE and Opera in a few days with minimal difficulty. CSSReset should be the basis for ALL website development and Yahoo should get a fucking medal for creating it. Cheers guys <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
<br clear="all"/></p>
<h2><a href="http://www.pixelmator.com/">Pixelmator</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080027.jpg" height="137" width="160" border="1" hspace="4" vspace="4" alt="200804080027" style="float:left; border:0px" />Pixelmator is a nice image editor the supports PSD's and layers. I got it as part of a <a href="http://www.macheist.com/">MacHeist</a> bundle and just started using it rather then paying hundreds of quid for Photoshop. Because it supports PSD's I can still work with artists who quite rightly want to use Photoshop.<br />
<br clear="all"/></p>
<h2><a href="http://www.vmware.com/mac">VMWare Fusion</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080027-1.jpg" height="138" width="168" border="1" hspace="4" vspace="4" alt="200804080027-1" style="float:left; border:0px" />Working on a mac makes it hard to get Internet Explorer working. I don't want or need a PC so VMWare comes to the rescue. VMWare is an OS virtualisation package that basically allows me to run various versions on Windows, Linux and BSD in a window. So I can run IE 5.5, 6.0 and 7 in separate virtual instances and check compatibility across IE5.5+, Safari, FireFox 2+ and Opera 9+. Since I'm a one man operation time consuming and boring tasks like this need to be made as painless as possible... or they won't get done.<br />
<br clear="all"/></p>
<h2><a href="http://www.getfirebug.com/">Firebug</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080029.jpg" height="154" width="162" border="1" hspace="4" vspace="4" alt="200804080029" style="float:left; border:0px" />Firebug is an extension for Firefox that allows you to examine pages and page elements to see how their layout has been calculated but it also allows you to debug Javascript inside the browser. It far exceeds IE's rather forced script debugger compatibility or .NET integration. This tool saved me months of debugging and more importantly sped up the learning curve for web development.<br />
<br clear="all"/></p>
<h2><a href="http://www.wingware.com/">Wingware IDE</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080030.jpg" height="139" width="166" border="1" hspace="4" vspace="4" alt="200804080030" style="float:left; border:0px" />There were times when I needed to debug fiddly python code and the python command line debugger just wasn't cutting it. I turned to Wingware's IDE for debugging and it served me very well. I only used it a few times though.</p>
<p><br clear="all"/></p>
<h2><a href="http://www.neooffice.org/">NeoOffice</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080031.jpg" height="130" width="144" border="1" hspace="4" vspace="4" alt="200804080031" style="float:left; border:0px" />Neooffice is a Mac port of Open Office. It's a good replacement for Claris or MS Office. I only needed to write a few letters to lawyers and such but it's good to not have to pay Â£500 for the privilege. I did use it a lot for opening up 50Mb csv files and it coped quite well with it.<br />
<br clear="all"/></p>
<h2><a href="http://www.python.org/">Python</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080031-1.jpg" height="71" width="211" border="1" hspace="4" vspace="4" alt="200804080031-1" style="float:left; border:0px" />Well this is pretty obvious, TurboGears uses Python so I am forced to work with it. Well luckily python is one of the best languages to do anything in. With a vast array of modules it's really quick to create scripts to process data for your website. As an affiliate for many music companies (iTunes, HMV, Play, Amazon, ...) I get access to huge XML and CSV files with their latest prices, stock and shipping information. Because of python's flexibility it is easy to merge this data in to New Metal Army.<br />
<br clear="all"/></p>
<h2><a href="http://turbogears.org/">TurboGears</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080110.jpg" height="130" width="129" border="1" hspace="4" vspace="4" alt="200804080110" style="float:left; border:0px" /><br />
TurboGears is a no brainer here. It's the web framework New Metal Army sits upon. For me though TG was more then a framework. TG comes with a great community bundled for free. I learned a lot just reading the mailing list. I also learned a lot by reading the code for TurboGears itself. It's well written and cleanly constructed. There is some advanced python on there but I don't think anything is overly complicated. Python is a great language to read and I think more programmers need to learn that they CAN dive in to most code and quickly work out what is going on.</p>
<p><br clear="all"/></p>
<h2><a href="http://www.postgresql.org/">PostgreSQL</a></h2>
<p><img src="http://www.luckydonkey.com/wp-content/uploads/2008/04/200804080118.jpg" height="103" width="130" border="1" hspace="4" vspace="4" alt="200804080118" style="float:left; border:0px" /><br />
Postgres has always been my database of choice. Unfortunately I have no real reason for this other then it's always covered my needs and it is standards compliant so I expect it to cover my needs for the foreseeable future. TurboGears uses an <a href="http://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> mapper (<a href="http://www.sqlalchemy.org/">SQLAlchemy</a>) between it and the database so I could swap Postgres for MSSQL, MySQL, Firebird, Oracle or a number of others. Postgres serves New Metal Army VERY well.</p>
<p><map name='google_ad_map_201_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/201?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_201_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=201&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F04%2F19%2Fturbogears-development-enviroment%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/04/19/turbogears-development-enviroment/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>New Metal Army: Overview</title>
		<link>http://www.luckydonkey.com/2008/04/03/new-metal-army-overview/</link>
		<comments>http://www.luckydonkey.com/2008/04/03/new-metal-army-overview/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 18:37:55 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[NewMetalArmy]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/2008/04/03/new-metal-army-overview/</guid>
		<description><![CDATA[For the last year I've been working on a project in TurboGears. Well no I can basically say version 1.0 if New Metal Army is done. It's been a long time (nearly a year) and it's far from complete but what is there is basically feature complete and it makes a nice site. Here is [...]]]></description>
			<content:encoded><![CDATA[<p>For the last year I've been working on a project in <a href="http://www.turbogears.org">TurboGears</a>. Well no I can basically say version 1.0 if <a href="http://www.newmetalarmy.com">New Metal Army</a> is done. It's been a long time (nearly a year) and it's far from complete but what is there is basically feature complete and it makes a nice site. </p>
<p>Here is a quick summary of New Metal Army:</p>
<ul>
<li>Pulls together the news from the top metal and rock webites from around the world. All news is tagged and associated with appropriate bands</li>
<li>Has full gig listings for the uk rock/metal scene with full venue details and links to buy tickets</li>
<li>Brings together band details from wikipedia, flickr, youtube, musicbrainz and amazon</li>
</ul>
<p>As it currently stands there are 2500+ bands, 400+ gigs, 100+ venues, 500,000+ band pictures and 1000000+ band videos and it's growing all the time.</p>
<p>I've learned a lot about the internet doing this project. Most of my time was spent researching different ways to scrape and understand websites. Here is a summary of what I learned:</p>
<ul>
<li>The internet is a mess. There are a lot of sites with HTML that isn't just slightly wrong but VERY wrong.</li>
<li><a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> goes a long way to parsing the bad markup in the internet.</li>
<li>Structural markup (bold, italic, div etc) were the least of my worries. The semantic meaning of the data is very hard to discern. Now this is obvious but when I started I didn't really think about it. I assumed that <a href="http://microformats.org/">MicroFormats</a> would come to my rescue... but no one uses them (well very few people use them). I must confess that I have a task in my <a href="http://trac.edgewall.org/">Trac</a> to add them but it's not a priority at the moment. So even I don't use them!</li>
<li>Even with MicroFormats the data I needed is tainted by human input (like most of the internet). I deal a lot with band names and bands names are often misspelt and adjectives like 'a' and 'the' added and removed.</li>
<li>Following on from spellings: people in the world still insist on using foreign languages that have <a href="http://en.wikipedia.org/wiki/Heavy_metal_umlaut">funny accents</a> and despite what you <a href="http://boodebr.org/main/python/all-about-python-and-unicode">read</a> unicode, while simple to code in python, is not simple to <a href="http://www.imdb.com/title/tt0083943/">think in</a>. When will everyone learn to speak local <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>A human algorithm for tagging things is... to tag things with a scatter gun approach. The code base looks in flickr for pictures of bands. It does this by looking at the tags associated with a picture. The trouble is when someone takes some photos at a concert they mass upload them and tag them all with the names of all the bands at the concert and sometimes with bands like the bands at the concert... not to useful.</li>
<li>Python does scale pretty well to large projects... but it's easy to get 'leaks' which make your heap grow and grow. They aren't really leaks they are normally lists of things that you are forgetting to tidy up and python is dutifully holding them for you. This is something I really didn't think about until I deployed the site and associated tools and noticed that my 'Job Runner' (threaded application that ran various jobs) just grew and grew.</li>
<li>Before you start writing anything in Python look for a module on the internet that does it. If you can't find a module to do it then write your own. However, write you own module knowing this: As soon as you have finished, somehow you will find a module that is more complete then yours on the internet and you will kick yourself for not finding it before!</li>
<li>Zombies rock... everyone likes zombie and Simon (my Zombie) is no exception to this <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ul>
<p>I intend to add some articles on how I did various bits and bobs over the next few weeks.</p>
<p><map name='google_ad_map_184_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/184?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_184_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=184&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F04%2F03%2Fnew-metal-army-overview%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/04/03/new-metal-army-overview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FreeBSD 6.3 and Turbogears</title>
		<link>http://www.luckydonkey.com/2008/01/19/freebsd-63-and-turbogears/</link>
		<comments>http://www.luckydonkey.com/2008/01/19/freebsd-63-and-turbogears/#comments</comments>
		<pubDate>Sat, 19 Jan 2008 15:21:14 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[FreeBSD]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[TurboGears]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/2008/01/19/freebsd-63-and-turbogears/</guid>
		<description><![CDATA[I upgraded a test server to FreeBSD 6.3 (released a few days ago) and all was working well apart from my TurboGears app. I run a TurboGears instance behind mod_wsgi and it wouldn't start. Here is the error I got in http_errors.log &#91;Sat Jan 19 11:32:42 2008&#93; &#91;error&#93; &#91;client 207.155.93.149&#93; mod_wsgi &#40;pid=1292&#41;: Exception occurred within [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<br clear="all">I upgraded a test server to FreeBSD 6.3 (<a href="http://docs.freebsd.org/cgi/getmsg.cgi?fetch=15458+0+current/freebsd-announce">released a few days ago</a>) and all was working well apart from my TurboGears app. I run a TurboGears instance behind <a href="http://code.google.com/p/modwsgi/">mod_wsgi</a> and it wouldn't start. Here is the error I got in http_errors.log</p>
<pre class="bash"><span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Jan <span style="color: #000000;">19</span> <span style="color: #000000;">11</span>:<span style="color: #000000;">32</span>:<span style="color: #000000;">42</span> <span style="color: #000000;">2008</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>error<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>client <span style="color: #000000;">207.155</span><span style="color: #000000;">.93</span><span style="color: #000000;">.149</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> mod_wsgi <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">pid=</span><span style="color: #000000;">1292</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>: Exception occurred within WSGI script <span style="color: #ff0000;">'/home/m/release1.0/apache/turbogears.wsgi'</span>.
<span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Jan <span style="color: #000000;">19</span> <span style="color: #000000;">11</span>:<span style="color: #000000;">32</span>:<span style="color: #000000;">42</span> <span style="color: #000000;">2008</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>error<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>client <span style="color: #000000;">207.155</span><span style="color: #000000;">.93</span><span style="color: #000000;">.149</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> Traceback <span style="color: #7a0874; font-weight: bold;">&#40;</span>most recent call <span style="color: #c20cb9; font-weight: bold;">last</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
<span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Jan <span style="color: #000000;">19</span> <span style="color: #000000;">11</span>:<span style="color: #000000;">32</span>:<span style="color: #000000;">42</span> <span style="color: #000000;">2008</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>error<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>client <span style="color: #000000;">207.155</span><span style="color: #000000;">.93</span><span style="color: #000000;">.149</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>   File <span style="color: #ff0000;">&quot;/home/m/release1.0/apache/turbogears.wsgi&quot;</span>, line <span style="color: #000000;">67</span>, <span style="color: #000000; font-weight: bold;">in</span> &lt;module&gt;
<span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Jan <span style="color: #000000;">19</span> <span style="color: #000000;">11</span>:<span style="color: #000000;">32</span>:<span style="color: #000000;">42</span> <span style="color: #000000;">2008</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>error<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>client <span style="color: #000000;">207.155</span><span style="color: #000000;">.93</span><span style="color: #000000;">.149</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>     import turbogears
<span style="color: #7a0874; font-weight: bold;">&#91;</span>Sat Jan <span style="color: #000000;">19</span> <span style="color: #000000;">11</span>:<span style="color: #000000;">32</span>:<span style="color: #000000;">42</span> <span style="color: #000000;">2008</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>error<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>client <span style="color: #000000;">207.155</span><span style="color: #000000;">.93</span><span style="color: #000000;">.149</span><span style="color: #7a0874; font-weight: bold;">&#93;</span> ImportError: No module named turbogears</pre>
<p>That's odd. I've not uninstalled TurboGears and my background processes that #import TurboGears still work. Infact if I go to the python command line and type #import TurboGears it all works... bugger.</p>
<p>To complicate matters (in this case) I use a <a href="http://pypi.python.org/pypi/workingenv.py">workingenv</a> to contain a very specific version of TurboGears and all of it's dependencies. In order for the wsgi script to access the sandbox environment I use an excellent <a href="http://swapoff.org/wiki/blog/2007-03-20-activating-a-workingenv-from-python">script</a> which tweaks the runtime environment to include the paths in a working env. My first though is that something here had gone wrong. So I turned to prints and some basic error capture.</p>
<pre class="python"><span style="color: #808080; font-style: italic;"># Load all distributions into the working set.</span>
<span style="color: #ff7700;font-weight:bold;">from</span> pkg_resources <span style="color: #ff7700;font-weight:bold;">import</span> working_set, Environment
&nbsp;
env = Environment<span style="color: black;">&#40;</span>root<span style="color: black;">&#41;</span>
env.<span style="color: black;">scan</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
distributions, errors = working_set.<span style="color: black;">find_plugins</span><span style="color: black;">&#40;</span>env<span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">for</span> dist <span style="color: #ff7700;font-weight:bold;">in</span> distributions:
    working_set.<span style="color: black;">add</span><span style="color: black;">&#40;</span>dist<span style="color: black;">&#41;</span></pre>
<p>Printing out errors revealed:</p>
<pre class="bash">errors:
<span style="color: #7a0874; font-weight: bold;">&#123;</span>Amara <span style="color: #000000;">1.2</span><span style="color: #000000;">.0</span><span style="color: #000000;">.2</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>/usr/home/m/tgenv1_0_32/lib/python2<span style="color: #000000;">.5</span>/Amara<span style="color: #000000;">-1.2</span><span style="color: #000000;">.0</span><span style="color: #000000;">.2</span>-py2<span style="color: #000000;">.5</span>.egg<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
   DistributionNotFound<span style="color: #7a0874; font-weight: bold;">&#40;</span>Requirement.parse<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'4Suite-XML&gt;=1.0.2'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #7a0874; font-weight: bold;">&#41;</span>,
TGCaptcha <span style="color: #000000;">0.11</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>/usr/home/m/tgenv1_0_32/lib/python2<span style="color: #000000;">.5</span>/TGCaptcha<span style="color: #000000;">-0.11</span>-py2<span style="color: #000000;">.5</span>.egg<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
   DistributionNotFound<span style="color: #7a0874; font-weight: bold;">&#40;</span>Requirement.parse<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">'pycrypto&gt;=2.0.1'</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>,<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
<p>Well I hadn't uninstalled those packages and I'm pretty sure that freebsd-update hadn't uninstalled them so where the hell have they gone! Looking in the workingenv sandbox package directory</p>
<pre class="bash"><span style="color: #c20cb9; font-weight: bold;">ls</span> -la /usr/home/m/tgenv1_0_32/lib/python2<span style="color: #000000;">.5</span>
4Suite_XML<span style="color: #000000;">-1.0</span><span style="color: #000000;">.2</span>-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
Amara<span style="color: #000000;">-1.2</span><span style="color: #000000;">.0</span><span style="color: #000000;">.2</span>-py2<span style="color: #000000;">.5</span>.egg
BeautifulSoup<span style="color: #000000;">-3.0</span><span style="color: #000000;">.5</span>-py2<span style="color: #000000;">.5</span>.egg
Cheetah<span style="color: #000000;">-2.0</span><span style="color: #000000;">.1</span>-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
Cheetah<span style="color: #000000;">-2</span>.0rc8-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
CherryPy<span style="color: #000000;">-2.2</span><span style="color: #000000;">.1</span>-py2<span style="color: #000000;">.5</span>.egg
...
PasteScript<span style="color: #000000;">-1.3</span><span style="color: #000000;">.6</span>-py2<span style="color: #000000;">.5</span>.egg
PyProtocols<span style="color: #000000;">-1</span>.0a0dev_r2302-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
Routes<span style="color: #000000;">-1.7</span><span style="color: #000000;">.1</span>-py2<span style="color: #000000;">.5</span>.egg
RuleDispatch<span style="color: #000000;">-0</span>.5a0.dev_r2306-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
SQLAlchemy<span style="color: #000000;">-0.3</span><span style="color: #000000;">.10</span>-py2<span style="color: #000000;">.5</span>.egg
...
moved_aside_site.py
psycopg2<span style="color: #000000;">-2.0</span><span style="color: #000000;">.6</span>-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
pycrypto<span style="color: #000000;">-2.0</span><span style="color: #000000;">.1</span>-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
python_dateutil<span style="color: #000000;">-1.3</span>-py2<span style="color: #000000;">.5</span>.egg
...
setuptools.pth
simplejson<span style="color: #000000;">-1.7</span><span style="color: #000000;">.3</span>-py2<span style="color: #000000;">.5</span>-freebsd<span style="color: #000000;">-6.2</span>-RELEASE-i386.egg
...
&nbsp;</pre>
<p>BUGGER, there are packages in there with the OS version number in that need to be updated:</p>
<pre class="bash">easy_install -U amara
easy_install -U pycrypto
easy_install -U psycopg2
...</pre>
<p>fixed all the problems and finally the site is up again <img src='http://www.luckydonkey.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  So I've fixed the problem but I don't know why my other processes and the python command line worked. If anyone knows, I love to know too. Cheers.</p>
<p><map name='google_ad_map_181_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/181?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_181_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=181&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F01%2F19%2Ffreebsd-63-and-turbogears%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/01/19/freebsd-63-and-turbogears/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python Style Plugins Made Easy</title>
		<link>http://www.luckydonkey.com/2008/01/02/python-style-plugins-made-easy/</link>
		<comments>http://www.luckydonkey.com/2008/01/02/python-style-plugins-made-easy/#comments</comments>
		<pubDate>Wed, 02 Jan 2008 23:29:48 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/2008/01/02/python-style-plugins-made-easy/</guid>
		<description><![CDATA[Sometimes you need to write code that loads python at runtime. Plugin architectures are a good example of this. Plugins allow extensibility but more importantly (for me at least) they enforce a strict API. Anyway, I've written this code a few times so I thought I'd modularize it. The specific bit of code I am [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<br clear="all"><br />
Sometimes you need to write code that loads python at runtime. Plugin architectures are a good example of this. Plugins allow extensibility but more importantly (for me at least) they enforce a strict API. Anyway, I've written this code a few times so I thought I'd modularize it.</p>
<p>The specific bit of code I am going to post is the python code to look for and load a series of python plugins. Plugins (in this case) are just classes that are subclasses of the Plugin base class. This plugin base class dictates the API that all plugins must implement. Here is an example plugin <a href="http://en.wikipedia.org/wiki/Class_(computer_science)#Abstract_classes">abstract</a>  base class</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">class</span> Plugin<span style="color: black;">&#40;</span><span style="color: #008000;">object</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> setup<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;called before the plugin is asked to do anything&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> teardown<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;called to allow the plugin to free anything&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> domagic<span style="color: black;">&#40;</span><span style="color: #008000;">self</span><span style="color: black;">&#41;</span>:
        <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;do whatever it is the plugin does&quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
        <span style="color: #ff7700;font-weight:bold;">raise</span> <span style="color: #008000;">NotImplementedError</span>
&nbsp;</pre>
<p>Here the is code to look for and return a list of classes that can be instantiated:</p>
<pre class="python"><span style="color: #ff7700;font-weight:bold;">def</span> find_subclasses<span style="color: black;">&#40;</span>path, cls<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;
    Find all subclass of cls in py files located below path
    (does look in sub directories)
&nbsp;
    @param path: the path to the top level folder to walk
    @type path: str
    @param cls: the base class that all subclasses should inherit from
    @type cls: class
    @rtype: list
    @return: a list if classes that are subclasses of cls
    &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
&nbsp;
    subclasses=<span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">def</span> look_for_subclass<span style="color: black;">&#40;</span>modulename<span style="color: black;">&#41;</span>:
        log.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;searching %s&quot;</span> % <span style="color: black;">&#40;</span>modulename<span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        module=<span style="color: #008000;">__import__</span><span style="color: black;">&#40;</span>modulename<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;">#walk the dictionaries to get to the last one</span>
        d=module.<span style="color: #0000cd;">__dict__</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> m <span style="color: #ff7700;font-weight:bold;">in</span> modulename.<span style="color: black;">split</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">1</span>:<span style="color: black;">&#93;</span>:
            d=d<span style="color: black;">&#91;</span>m<span style="color: black;">&#93;</span>.<span style="color: #0000cd;">__dict__</span>
&nbsp;
        <span style="color: #808080; font-style: italic;">#look through this dictionary for things</span>
        <span style="color: #808080; font-style: italic;">#that are subclass of Job</span>
        <span style="color: #808080; font-style: italic;">#but are not Job itself</span>
        <span style="color: #ff7700;font-weight:bold;">for</span> key, entry <span style="color: #ff7700;font-weight:bold;">in</span> d.<span style="color: black;">items</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
            <span style="color: #ff7700;font-weight:bold;">if</span> key == cls.__name__:
                <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
            <span style="color: #ff7700;font-weight:bold;">try</span>:
                <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">issubclass</span><span style="color: black;">&#40;</span>entry, cls<span style="color: black;">&#41;</span>:
                    log.<span style="color: black;">debug</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;Found subclass: &quot;</span>+key<span style="color: black;">&#41;</span>
                    subclasses.<span style="color: black;">append</span><span style="color: black;">&#40;</span>entry<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">TypeError</span>:
                <span style="color: #808080; font-style: italic;">#this happens when a non-type is passed in to issubclass. We</span>
                <span style="color: #808080; font-style: italic;">#don't care as it can't be a subclass of Job if it isn't a</span>
                <span style="color: #808080; font-style: italic;">#type</span>
                <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> root, dirs, files <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">walk</span><span style="color: black;">&#40;</span>path<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">for</span> name <span style="color: #ff7700;font-weight:bold;">in</span> files:
            <span style="color: #ff7700;font-weight:bold;">if</span> name.<span style="color: black;">endswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;.py&quot;</span><span style="color: black;">&#41;</span> <span style="color: #ff7700;font-weight:bold;">and</span> <span style="color: #ff7700;font-weight:bold;">not</span> name.<span style="color: black;">startswith</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;__&quot;</span><span style="color: black;">&#41;</span>:
                path = <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">join</span><span style="color: black;">&#40;</span>root, name<span style="color: black;">&#41;</span>
                modulename = path.<span style="color: black;">rsplit</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'.'</span>, <span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span>.<span style="color: black;">replace</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/'</span>, <span style="color: #483d8b;">'.'</span><span style="color: black;">&#41;</span>
                look_for_subclass<span style="color: black;">&#40;</span>modulename<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> subclasses
&nbsp;</pre>
<p>and here is how you would call it:</p>
<pre class="python">classes = find_subclasses<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;./pluginsfolder/&quot;</span>, Plugin<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">#lets create an instance of the first class</span>
inst = classes<span style="color: black;">&#91;</span><span style="color: #ff4500;">0</span><span style="color: black;">&#93;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;</pre>
<p>So there you go, create folder of python files with classes in them that subclass the Plugin class and you are away.</p>
<p><map name='google_ad_map_177_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/177?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_177_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=177&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2008%2F01%2F02%2Fpython-style-plugins-made-easy%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2008/01/02/python-style-plugins-made-easy/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Total Guitar Magazine: Decryption Error</title>
		<link>http://www.luckydonkey.com/2007/12/04/total-guitar-magazine-decryption-error/</link>
		<comments>http://www.luckydonkey.com/2007/12/04/total-guitar-magazine-decryption-error/#comments</comments>
		<pubDate>Tue, 04 Dec 2007 17:47:41 +0000</pubDate>
		<dc:creator>dazza</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Rant]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://www.luckydonkey.com/2007/12/04/total-guitar-magazine-decryption-error/</guid>
		<description><![CDATA[Like most metalheads I own a guitar I can't play. I also subscribe to Total Guitar Magazine. This month I noticed that I couldn't decrypt the special 'VIP Area' of the CD. Basically If I was using a PPC Mac I would be able to decrypt the data. It seems they have included the PPC [...]]]></description>
			<content:encoded><![CDATA[<p><script type="text/javascript"><!--
google_ad_client = "pub-9998980871049158";
google_ad_slot = "6052810016";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
<br clear="all"><br />
Like most metalheads I own a guitar I can't play. I also subscribe to Total Guitar Magazine. This month I noticed that I couldn't decrypt the special 'VIP Area' of the CD.</p>
<p style="text-align:center;"><img src="http://www.luckydonkey.com/wp-content/uploads/2007/12/bugger-1.jpg" height="309" width="430" border="1" hspace="4" vspace="4" alt="Bugger-1" /></p>
<p>Basically If I was using a PPC Mac I would be able to decrypt the data. It seems they have included the PPC only shared library for blowfish. Hmm. Well as it happens I have a copy of the x86 library that I can use to decrypt the data.</p>
<p>If you are suffering from this problem:</p>
<ol>
<li>Download the library <a href="http://www.luckydonkey.com/Blowfish.so">here</a>.
</li>
<li>Look inside any OSX app by right clicking (or CTRL clicking) on the application icon and selecting 'Show Package Contents'<br />
<img src="http://www.luckydonkey.com/wp-content/uploads/2007/12/showcontent.jpg" height="314" width="246" border="1" hspace="4" vspace="4" alt="Showcontent" />
</li>
<li>Now navigate down to
<pre>Contents/Resources/lib/python2.5/lib-dynload/Crypto/Cipher/</pre>
</li>
<li>Copy the Blowfish.so into the Cipher Folder, there should be one there already so you'll be asked if you want to replace the existing one</li>
</ol>
<p>You should be able to run the decryptor.app now and get access to your MP3s.<br />
Whoever makes this application should be able to make the decryption library Universal so lets hope they do that in the future.</p>
<p><map name='google_ad_map_176_afea9fcd39d8b84a'>
<area shape='rect' href='http://imageads.googleadservices.com/pagead/imgclick/176?pos=0' coords='1,2,367,28' />
<area shape='rect' href='http://services.google.com/feedback/abg' coords='384,10,453,23'/></map>
<img usemap='#google_ad_map_176_afea9fcd39d8b84a' border='0' src='http://imageads.googleadservices.com/pagead/ads?format=468x30_aff_img&amp;client=&amp;channel=&amp;output=png&amp;cuid=176&amp;url= http%3A%2F%2Fwww.luckydonkey.com%2F2007%2F12%2F04%2Ftotal-guitar-magazine-decryption-error%2F' /></p>]]></content:encoded>
			<wfw:commentRss>http://www.luckydonkey.com/2007/12/04/total-guitar-magazine-decryption-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
