<?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>tenshu.net &#187; Python</title>
	<atom:link href="http://www.tenshu.net/archives/category/techie/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.tenshu.net</link>
	<description>Pondering the mystery...</description>
	<lastBuildDate>Tue, 24 Aug 2010 21:14:39 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Terminator 0.95 released!</title>
		<link>https://launchpad.net/terminator/+announcement/6594</link>
		<comments>https://launchpad.net/terminator/+announcement/6594#comments</comments>
		<pubDate>Tue, 24 Aug 2010 21:14:39 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">tag:launchpad.net,2010-08-24:/+announcement/6594</guid>
		<description><![CDATA[This release is mostly to bring a couple of important compatibility fixes with the newest pre-release of VTE, but we also have some updated translations, improved error handling and two new features for you. The features are a URL handler plugin for Ma...]]></description>
			<content:encoded><![CDATA[<p>This release is mostly to bring a couple of important compatibility fixes with the newest pre-release of VTE, but we also have some updated translations, improved error handling and two new features for you. The features are a URL handler plugin for Maven by Julien Nicolaud and a DBus server that was the result of some work with Andrea Corbellini - for now the only thing this is useful for is opening additional Terminator windows without spawning a new process, but we'll be exploring options in the future to allow more control and interaction with Terminator processes.</p>]]></content:encoded>
			<wfw:commentRss>https://launchpad.net/terminator/+announcement/6594/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Who wants to see something really ugly?</title>
		<link>http://www.tenshu.net/archives/2010/07/06/who-wants-to-see-something-really-ugly/</link>
		<comments>http://www.tenshu.net/archives/2010/07/06/who-wants-to-see-something-really-ugly/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 11:33:42 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=10123</guid>
		<description><![CDATA[I think it should be abundantly clear from my postings here that I&#8217;m not a very good programmer, and this means I give myself a lot of free rope to do some very stupid things.
I&#8217;m in constant need of debugging information and in Terminator particularly where we have lots of objects all interacting and reparenting [...]]]></description>
			<content:encoded><![CDATA[<p>I think it should be abundantly clear from my postings here that I&#8217;m not a very good programmer, and this means I give myself a lot of free rope to do some very stupid things.</p>
<p>I&#8217;m in constant need of debugging information and in Terminator particularly where we have lots of objects all interacting and reparenting all the time. We&#8217;ve had a simple dbg() method for a long time, but I was getting very bored of typing out dbg(&#8216;Class::method:: Some message about %d&#8217; % foo), so I decided to see what could be done about inferring the Class and method parts of the message.</p>
<p>It turns out that python is very good at introspecting its own runtime, so back in January, armed with my own stupidity and some help from various folks on the Internet, I came up with the following:</p>
<pre># set this to true to enable debugging output
DEBUG = False
# set this to true to additionally list filenames in debugging
DEBUGFILES = False
# list of classes to show debugging for. empty list means show all classes
DEBUGCLASSES = []
# list of methods to show debugging for. empty list means show all methods
DEBUGMETHODS = []

def dbg(log = ""):
    """Print a message if debugging is enabled"""
    if DEBUG:
        stackitem = inspect.stack()[1]
        parent_frame = stackitem[0]
        method = parent_frame.f_code.co_name
        names, varargs, keywords, local_vars = inspect.getargvalues(parent_frame)
        try:
            self_name = names[0]
            classname = local_vars[self_name].__class__.__name__
        except IndexError:
            classname = "noclass"
        if DEBUGFILES:
            line = stackitem[2]
            filename = parent_frame.f_code.co_filename
            extra = " (%s:%s)" % (filename, line)
        else:
            extra = ""
        if DEBUGCLASSES != [] and classname not in DEBUGCLASSES:
            return
        if DEBUGMETHODS != [] and method not in DEBUGMETHODS:
            return
        try:
            print >> sys.stderr, "%s::%s: %s%s" % (classname, method, log, extra)
        except IOError:
            pass
</pre>
<p>How&#8217;s about that for shockingly bad? ;)<br />
It also adds a really impressive amount of overhead to the execution time.<br />
I added the DEBUGCLASSES and DEBUGMETHODS lists so I could cut down on the huge amount of output &#8211; these are hooked up to command line options, so you can do something like &#8220;terminator -d &#8211;debug-classes=Terminal&#8221; and only receive debugging messages from the Terminal module.</p>
<p>I&#8217;m not exactly sure what I hope to gain from this post, other than ridicule on the Internet, but maybe, just maybe, someone will pop up and point out how stupid I am in a way that turns this into a 2 line, low-overhead function :D</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/07/06/who-wants-to-see-something-really-ugly/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>My python also spins webs</title>
		<link>http://www.tenshu.net/archives/2010/07/06/my-python-also-spins-webs/</link>
		<comments>http://www.tenshu.net/archives/2010/07/06/my-python-also-spins-webs/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 06:45:06 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/archives/2010/07/06/my-python-also-spins-webs/</guid>
		<description><![CDATA[With Terminator 0.94 released I&#8217;m turning my little brain onto an idea I have for a web service and obviously I&#8217;m sticking with python.
Clearly writing all the web gubbins by hand is mental, so I&#8217;m playing with Flask, a microframework for web apps. So far I&#8217;m really liking it, but it&#8217;s taken a while to [...]]]></description>
			<content:encoded><![CDATA[<p>With Terminator 0.94 released I&#8217;m turning my little brain onto an idea I have for a web service and obviously I&#8217;m sticking with python.<br />
Clearly writing all the web gubbins by hand is mental, so I&#8217;m playing with Flask, a microframework for web apps. So far I&#8217;m really liking it, but it&#8217;s taken a while to figure it and sqlalchemy out.<br />
I&#8217;m not at all convinced that this is going to be in any way scalable, but it&#8217;s a nice way to test my idea :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/07/06/my-python-also-spins-webs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Terminator 0.94 released!</title>
		<link>https://launchpad.net/terminator/+announcement/6261</link>
		<comments>https://launchpad.net/terminator/+announcement/6261#comments</comments>
		<pubDate>Sun, 04 Jul 2010 18:15:47 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">tag:launchpad.net,2010-07-04:/+announcement/6261</guid>
		<description><![CDATA[Lots of bug fixes and some improvements to the preferences are in this release, as well as a couple of new plugins for watching terminals for activity, or taking screenshots of individual terminals.
See the changelog for full details.]]></description>
			<content:encoded><![CDATA[<p>Lots of bug fixes and some improvements to the preferences are in this release, as well as a couple of new plugins for watching terminals for activity, or taking screenshots of individual terminals.<br />
See the changelog for full details.</p>]]></content:encoded>
			<wfw:commentRss>https://launchpad.net/terminator/+announcement/6261/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A good day</title>
		<link>http://www.tenshu.net/archives/2010/07/04/a-good-day-2/</link>
		<comments>http://www.tenshu.net/archives/2010/07/04/a-good-day-2/#comments</comments>
		<pubDate>Sat, 03 Jul 2010 23:40:08 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Friends]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Music]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/archives/2010/07/04/a-good-day-2/</guid>
		<description><![CDATA[Today has been about creating, not consuming. Apart from half-watching Primal Fear with Rike, I have spent the day fixing bugs in Terminator and playing with the Akai Synthstation app on my iPad. I suspect I&#8217;m not going to be ruling the clubs anytime soon, and the UI is pretty dreadful for composing music, but [...]]]></description>
			<content:encoded><![CDATA[<p>Today has been about creating, not consuming. Apart from half-watching Primal Fear with Rike, I have spent the day fixing bugs in Terminator and playing with the Akai Synthstation app on my iPad. I suspect I&#8217;m not going to be ruling the clubs anytime soon, and the UI is pretty dreadful for composing music, but it has a good library of sounds and synth mangling knobs :)<br />
I even filmed myself playing some of the parts and edited them together into a little music video, but it&#8217;s really very poor ;)<br />
Rike&#8217;s going to be out for most of tomorrow, so I have to decide between doing more of what I&#8217;ve been doing today, playing PS3 games or going out myself. Tricky!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/07/04/a-good-day-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python decisions</title>
		<link>http://www.tenshu.net/archives/2010/06/03/python-decisions/</link>
		<comments>http://www.tenshu.net/archives/2010/06/03/python-decisions/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 21:06:31 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=8573</guid>
		<description><![CDATA[Every time I find myself hacking on some Python I find myself second guessing all sorts of tiny design decisions and so I figure the only way to get any kind of perspective on them is to talk about them. Either I&#8217;ll achieve more clarity through constructing explanations of what I was thinking, or people [...]]]></description>
			<content:encoded><![CDATA[<p>Every time I find myself hacking on some Python I find myself second guessing all sorts of tiny design decisions and so I figure the only way to get any kind of perspective on them is to talk about them. Either I&#8217;ll achieve more clarity through constructing explanations of what I was thinking, or people will comment with useful insights. Hopefully the latter, but this is hardly the most popular blog in the world ;)<br />
So. What shall we look at first. Well, I just hacked up a tiny script last night to answer a simple question:</p>
<p style="padding-left: 30px;"><em> Is most of my music collection from the 90s?</em></p>
<address style="padding-left: 30px;"> </address>
<p>Obviously what I want to do here is examine the ID3 tags of the files in my music collection and see how they&#8217;re distributed. A quick search with apt showed that Ubuntu 10.04 has two python libraries for dealing with ID3 tags and a quick play with each suggested that the one with the API most relevant to my interests was <a title="Install eyeD3" href="apt:python-eyed3">eyeD3</a>. After a few test iterations of the script I was getting bored of waiting for it to silently scan the roughly 4000 MP3s I have, so I did another quick search and found a <a title="Install progressbar" href="apt:python-progressbar">progress bar </a>library.</p>
<p>So that&#8217;s all of the motive and opportunity established, now let&#8217;s examine the means to the end. If you want to follow along at home, the whole script is <a title="musicdecades.py.txt" href="/wp-content/uploads/2010/06/musicdecades.py_.txt">here</a>.</p>
<p style="padding-left: 30px;">
<pre style="padding-left: 30px;">try:</pre>
<pre style="padding-left: 30px;"> import eyeD3</pre>
<pre style="padding-left: 30px;"> import progressbar as pbar</pre>
<pre style="padding-left: 30px;">except ImportError:</pre>
<pre style="padding-left: 30px;">print("You should make sure python-eyed3 and python-progressbar \</pre>
<pre style="padding-left: 30px;">are installed")</pre>
<pre style="padding-left: 30px;"> sys.exit(1)</pre>
<p>First off this is the section where I&#8217;m importing the two non-default python libraries that I depend on. I want to provide a good experience when they&#8217;re not installed, so I catch the exception and tell people the Debian/Ubuntu package names they need, and exit gracefully. I rename the progressbar module as I import it just because &#8220;progressbar&#8221; is annoyingly long as a name, and I don&#8217;t like doing &#8220;from foo import *&#8221;.</p>
<p>Skipping further on, we find the code that extracts the ID3 year tag:</p>
<pre style="padding-left: 30px;">year = tag.getYear() or 'Unknown'
</pre>
<p>This is something I&#8217;m really not sure about the &#8220;correctness&#8221; of; One of the reasons I went with the eyeD3 library was that the getYear() method returns None if it can&#8217;t find any data, but I don&#8217;t really want to capture the result, then test the result explicitly and if it&#8217;s None set the value to &#8220;Unknown&#8221;, so I went with the above code which only needs a single line and is (IMHO) highly readable.</p>
<p>This is ultimately the crux of the entire program &#8211; we&#8217;ve now collected the year, so we can work out which decade it&#8217;s from:</p>
<pre style="padding-left: 30px;">if year is not 'Unknown':
 year = "%s0s" % str(year)[:3]
</pre>
<p>If this isn&#8217;t an unknown year we chop the final digit off the year and replace it with a zero. Job done!</p>
<p>Next up, another style question. Rather than store the year we just processed I want to know how many of each decade have been found, so the obvious choice is a dict where the keys are the decades and the values are the number of times each decade has been found. One option would be to pre-fill the dict with all the decades, each with a value of zero, but that seems redundant and ugly, so instead I start out with an empty dict. This presents a challenge &#8211; if we find a decade that isn&#8217;t already a key in the dict (which will frequently be the case) we need to notice that and add it. We could do this by pre-emptively testing the dict with its has_key() method, but that struck me as annoyingly wordy, so I went with:</p>
<pre style="padding-left: 30px;">try:</pre>
<pre style="padding-left: 30px;"> years[year] += 1</pre>
<pre style="padding-left: 30px;">except KeyError:</pre>
<pre style="padding-left: 30px;"> years[year] = 1</pre>
<p>If we are incrementing a year that isn&#8217;t already in the dict, python will raise a KeyError, at which point we know what&#8217;s happened and know the correct value is 1, so we just set it explicitly. Seems like the simplest solution, but is it the sanest?</p>
<p>The only other thing I wanted to say is a complaint &#8211; having built up the dict I then want to print it nicely, so I have a quick list comprehension to produce a list of strings of the format &#8220;19xx: yy&#8221; (i.e. the decade and the final number of tracks found for that decade), which I then join together using:</p>
<pre style="padding-left: 30px;">', '.join(OUTPUT)</pre>
<p>which I hate! Why can&#8217;t I do:</p>
<pre style="padding-left: 30px;">OUTPUT.join(', ')</pre>
<p>(where &#8220;OUTPUT&#8221; is the list of strings). If that were possible, what I&#8217;d actually do is tack the .join() onto the end of the list comprehension and a single line would turn the dict into a printable string.</p>
<p>So there we have it, my thoughts on the structure of my script. I&#8217;d also add that I&#8217;ve become mildly obsessive about getting good scores from pylint on my code, which is why it&#8217;s rigorously formatted, docstring-ed and why the variable names in the __main__ section are in capitals.</p>
<p>What are your thoughts?</p>
<p>Oh, and the answer is no, most of my music is from the 2000s. The 1990s come in second :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/06/03/python-decisions/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>gtk icon cache search tool</title>
		<link>http://www.tenshu.net/archives/2010/05/12/gtk-icon-cache-search-tool/</link>
		<comments>http://www.tenshu.net/archives/2010/05/12/gtk-icon-cache-search-tool/#comments</comments>
		<pubDate>Wed, 12 May 2010 22:35:45 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=4867</guid>
		<description><![CDATA[Earlier on this evening I was asking the very excellent Ted Gould about a weird problem with my Gtk+ icon theme &#8211; an app I&#8217;d previously installed by hand in /usr/local/, but subsequently removed, had broken icons because Gtk+ was looking in /usr/local/share/icons/ instead of /usr/share/icons/.
We did a little digging and realised I had an [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier on this evening I was asking the very excellent Ted Gould about a weird problem with my Gtk+ icon theme &#8211; an app I&#8217;d previously installed by hand in /usr/local/, but subsequently removed, had broken icons because Gtk+ was looking in /usr/local/share/icons/ instead of /usr/share/icons/.</p>
<p>We did a little digging and realised I had an icon theme cache file in /usr/local/ that was overriding the one in /usr/. A bit of deleting later and it&#8217;s back, but in the process we whipped up a little bit of python to print out the filename of an icon given an icon name.</p>
<pre style="padding-left: 30px;">#!/usr/bin/python
# gtk-find-icon by Chris Jones &lt;cmsj@tenshu.net&gt;
# Copyright 2010. GPL v2.

import sys
import gtk

THEME = gtk.IconTheme()
ICON = THEME.lookup_icon(sys.argv[1],
 gtk.ICON_SIZE_MENU,
 gtk.ICON_LOOKUP_USE_BUILTIN)

if not ICON:
 print "None found"
else:
 print(ICON.get_filename())</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/05/12/gtk-icon-cache-search-tool/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Writing Terminator plugins</title>
		<link>http://www.tenshu.net/archives/2010/04/18/writing-terminator-plugins/</link>
		<comments>http://www.tenshu.net/archives/2010/04/18/writing-terminator-plugins/#comments</comments>
		<pubDate>Sun, 18 Apr 2010 20:30:43 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=814</guid>
		<description><![CDATA[Terminator Plugin HOWTO
One of the features of the new 0.9x series of Terminator releases that hasn&#8217;t had a huge amount of announcement/discussion yet is the plugin system. I&#8217;ve posted previously about the decisions that went into the design of the plugin framework, but I figured now would be a good time to look at how [...]]]></description>
			<content:encoded><![CDATA[<h2>Terminator Plugin HOWTO</h2>
<p>One of the features of the new 0.9x series of Terminator releases that hasn&#8217;t had a huge amount of announcement/discussion yet is the plugin system. I&#8217;ve posted previously about the decisions that went into the design of the plugin framework, but I figured now would be a good time to look at how to actually take advantage of it.</p>
<p>While the plugin system is really generic, so far there are only two points in the Terminator code that actually look for plugins &#8211; the Terminal context menu and the default URL opening code. If you find you&#8217;d like to write a plugin that interacts with a different part of Terminator, please let me know, I&#8217;d love to see some clever uses of plugins and I definitely want to expand the number of points that plugins can hook into.</p>
<h2>The basics of a plugin</h2>
<p>A plugin is a class in a .py file in terminatorlib/plugins or ~/.config/terminator/plugins, but not all classes are automatically treated as plugins. Terminator will examine each of the .py files it finds for a list called &#8216;available&#8217; and it will load each of the classes mentioned therein.</p>
<p>Additionally, it would be a good idea to import terminatorlib.plugin as that contains the base classes that other plugins should be derived from.</p>
<p>A quick example:</p>
<pre style="padding-left: 30px;">import terminatorlib.plugin as plugin
available = ['myfirstplugin']
class myfirstplugin(plugin.SomeBasePluginClass):
  etc.
</pre>
<p>So now let&#8217;s move on to the simplest type of plugin currently available in Terminator, a URL handler.</p>
<h2>URL Handlers</h2>
<p>This type of plugin adds new regular expressions to match text in the terminal that should be handled as URLs. We ship an example of this with Terminator, it&#8217;s a handler that adds support for the commonly used format for Launchpad. Ignoring the comments and the basics above, this is ultimately all it is:</p>
<pre style="padding-left: 30px;">class LaunchpadBugURLHandler(plugin.URLHandler):
  capabilities = ['url_handler']
  handler_name = 'launchpad_bug'
  match = '\\b(lp|LP):?\s?#?[0-9]+(,\s*#?[0-9]+)*\\b'
</pre>
<pre style="padding-left: 30px;">  def callback(self, url):
    for item in re.findall(r'[0-9]+', url):
      return('https://bugs.launchpad.net/bugs/%s' % item)</pre>
<p>That&#8217;s it! Let&#8217;s break it down a little to see the important things here:</p>
<ul>
<li>inherit from plugin.URLHandler if you want to handle URLs.</li>
<li>include &#8216;url_handler&#8217; in your capabilities list</li>
<li>URL handlers must specify a unique handler_name (no enforcement of uniqueness is performed by Terminator, so use some common sense with the namespace)</li>
<li>Terminator will call a method in your class called callback() and pass it the text that was matched. You must return a valid URL which will probably be based on this text.</li>
</ul>
<p>and that&#8217;s all there is to it really. Next time you start terminator you should find the pattern you added gets handled as a URL!</p>
<h2>Context menu items</h2>
<p>This type of plugin is a little more involved, but not a huge amount and as with URLHandler we ship an example in terminatorlib/plugins/custom_commands.py which is a plugin that allows users to add custom commands to be sent to the terminal when selected. This also brings a second aspect of making more complex plugins &#8211; storing configuration. Terminator&#8217;s shiny new configuration system (based on the excellent ConfigObj) exposes some API for plugins to use for loading and storing their configuration. The nuts and bolts here are:</p>
<pre style="padding-left: 30px;">import terminatorlib.plugin as plugin
from terminatorlib.config import Config
available = ['CustomCommandsMenu']
class CustomCommandsMenu(plugin.MenuItem):
  capabilities = ['terminal_menu']
  config = None
  def __init__(self):
    self.config = Config()
    myconfig = self.config.plugin_get_config(self.__class__.__name__)
    # Now extract valid data from sections{}
  def callback(self, menuitems, menu, terminal):
    menuitems.append(gtk.MenuItem('some jazz'))
</pre>
<p>This is a pretty simplified example, but it&#8217;s sufficient to insert a menu item that says &#8220;some jazz&#8221;. I&#8217;m not going to go into the detail of hooking up a handler to the &#8216;activate&#8217; event of the MenuItem or other PyGTK mechanics, but this gives you the basic detail. The method that Terminator will call from your class is again &#8220;callback()&#8221; and you get passed a list you should add your menu structure to, along with references to the main menu object and the related Terminal. As the plugin system expands and matures I&#8217;d like to be more formal about the API that plugins should expect to be able to rely on, rather than having them poke around inside classes like Config and Terminal. Suggestions are welcome :)</p>
<p>Regarding the configuration storage API &#8211; the value returned by Config.plugin_get_config() is just a dict, it&#8217;s whatever is currently configured for your plugin&#8217;s name in the Terminator config file. There&#8217;s no validation of this data, so you should pay attention to it containing valid data. You can then set whatever you want in this dict and pass it to Config().plugin_set_config() with the name of your class and then call Config().save() to flush this out to disk (I recommend that you be quite liberal about calling save()).</p>
<h2>Wrap up</h2>
<p>Right now that&#8217;s all there is to it. Please get in touch if you have any suggestions or questions &#8211; I&#8217;d love to ship more plugins with Terminator itself, and I can think of some great ideas. Probably the most useful thing would be something to help customise Terminator for heavy ssh users (see the earlier fork of Terminator called &#8217;ssherminator&#8217;)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/04/18/writing-terminator-plugins/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Terminator 0.93 released!</title>
		<link>https://launchpad.net/terminator/+announcement/5614</link>
		<comments>https://launchpad.net/terminator/+announcement/5614#comments</comments>
		<pubDate>Thu, 15 Apr 2010 20:34:01 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">tag:launchpad.net,2010-04-15:/+announcement/5614</guid>
		<description><![CDATA[Another week, another release focused on squashing as many bugs as possible. There's also one feature in this release - a patch from Kees Cook to add a preferences UI for the alternate_screen_scroll setting.
Please keep those bug reports coming, the re...]]></description>
			<content:encoded><![CDATA[<p>Another week, another release focused on squashing as many bugs as possible. There's also one feature in this release - a patch from Kees Cook to add a preferences UI for the alternate_<wbr></wbr>screen_<wbr></wbr>scroll setting.<br />
Please keep those bug reports coming, the response to the 0.9x series has been fantastic!</p>]]></content:encoded>
			<wfw:commentRss>https://launchpad.net/terminator/+announcement/5614/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Terminator 0.92 released</title>
		<link>https://launchpad.net/terminator/+announcement/5556</link>
		<comments>https://launchpad.net/terminator/+announcement/5556#comments</comments>
		<pubDate>Wed, 07 Apr 2010 21:50:58 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">tag:launchpad.net,2010-04-07:/+announcement/5556</guid>
		<description><![CDATA[Hot on the heels of 0.91 we have a new release for you. This is another bugfix release, stomping on as many regressions from 0.14 as we can find. Many, many thanks to all of the people who have been in touch with the project to tel us about the things ...]]></description>
			<content:encoded><![CDATA[<p>Hot on the heels of 0.91 we have a new release for you. This is another bugfix release, stomping on as many regressions from 0.14 as we can find. Many, many thanks to all of the people who have been in touch with the project to tel us about the things that are affecting them. If you find more regressions/bugs, please let us know!<br />
Also in this release the Palette section of the Profile editor in the Preferences GUI is now fully active, which means that all of the config file options should now be fully editable in the GUI.</p>]]></content:encoded>
			<wfw:commentRss>https://launchpad.net/terminator/+announcement/5556/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Terminator 0.90 released!</title>
		<link>https://launchpad.net/terminator/+announcement/5496</link>
		<comments>https://launchpad.net/terminator/+announcement/5496#comments</comments>
		<pubDate>Tue, 30 Mar 2010 22:22:12 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">tag:launchpad.net,2010-03-30:/+announcement/5496</guid>
		<description><![CDATA[After lots of work we're really very proud to announce that the completely re-worked Terminator 0.90 is now available! Hopefully we haven't introduced too many new bugs in exchange for the much requested features of being able to save layouts!]]></description>
			<content:encoded><![CDATA[After lots of work we're really very proud to announce that the completely re-worked Terminator 0.90 is now available! Hopefully we haven't introduced too many new bugs in exchange for the much requested features of being able to save layouts!]]></content:encoded>
			<wfw:commentRss>https://launchpad.net/terminator/+announcement/5496/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Heads up, new Terminator incoming</title>
		<link>http://www.tenshu.net/archives/2010/03/30/heads-up-new-terminator-incoming/</link>
		<comments>http://www.tenshu.net/archives/2010/03/30/heads-up-new-terminator-incoming/#comments</comments>
		<pubDate>Tue, 30 Mar 2010 13:07:56 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=800</guid>
		<description><![CDATA[Ok folks, I suck for not getting Terminator 0.90 released earlier and I suck for not having a bunch of bug fixes for 0.14 in Ubuntu Lucid.
I&#8217;m going to fix both tonight by releasing 0.90 and begging the lovely Ubuntu Universe folks to grant an exception to get it into Lucid.
Here&#8217;s hoping everything goes smoothly!
]]></description>
			<content:encoded><![CDATA[<p>Ok folks, I suck for not getting Terminator 0.90 released earlier and I suck for not having a bunch of bug fixes for 0.14 in Ubuntu Lucid.<br />
I&#8217;m going to fix both tonight by releasing 0.90 and begging the lovely Ubuntu Universe folks to grant an exception to get it into Lucid.<br />
Here&#8217;s hoping everything goes smoothly!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/03/30/heads-up-new-terminator-incoming/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>This is your captain speaking, Terminator has now landed!</title>
		<link>http://www.tenshu.net/archives/2010/01/21/this-is-your-captain-speaking-we-have-now-landed/</link>
		<comments>http://www.tenshu.net/archives/2010/01/21/this-is-your-captain-speaking-we-have-now-landed/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 18:35:23 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=383</guid>
		<description><![CDATA[I managed to finish off what I thought were the last few missing keyboard shortcuts during my lunch break today, but then realised that I&#8217;d missed two, but I was so excited an short of time that I decided to just go ahead and land the branch anyway!
So there it is &#8211; trunk is now [...]]]></description>
			<content:encoded><![CDATA[<p>I managed to finish off what I thought were the last few missing keyboard shortcuts during my lunch break today, but then realised that I&#8217;d missed two, but I was so excited an short of time that I decided to just go ahead and land the branch anyway!<br />
So there it is &#8211; trunk is now completely refactored and full of exciting new bugs. I noticed while I was working from it this afternoon that the transparency setting code wasn&#8217;t working, but I expect I can get that cleared up tonight :)</p>
<p>Now a bunch of bug fixing and a config converter and we can release!<br />
Thanks to everyone who has been testing so far.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/01/21/this-is-your-captain-speaking-we-have-now-landed/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Final approach for Terminator epic-refactor</title>
		<link>http://www.tenshu.net/archives/2010/01/21/final-approach-for-terminator-epic-refactor/</link>
		<comments>http://www.tenshu.net/archives/2010/01/21/final-approach-for-terminator-epic-refactor/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 00:21:09 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=380</guid>
		<description><![CDATA[I&#8217;m done hacking on the Terminator epic-refactor branch for the evening and the following has been achieved today (in chronological order):

Fix a bug in handling URLs dropped on the window
Implement directional navigation
Implement geometry hinting
Fix a bug in group emitting that cause &#8220;Broadcast off&#8221; and &#8220;Broadcast to all&#8221; to become inverted
Implement WM_URGENT bell handler

I&#8217;m really happy [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m done hacking on the Terminator epic-refactor branch for the evening and the following has been achieved today (in chronological order):</p>
<ul>
<li>Fix a bug in handling URLs dropped on the window</li>
<li>Implement directional navigation</li>
<li>Implement geometry hinting</li>
<li>Fix a bug in group emitting that cause &#8220;Broadcast off&#8221; and &#8220;Broadcast to all&#8221; to become inverted</li>
<li>Implement WM_URGENT bell handler</li>
</ul>
<p>I&#8217;m <em>really</em> happy with how this is going. All that is left to have feature parity with trunk, I think, is some keyboard shortcut handlers.</p>
<p>I&#8217;d still love to get more testing results to make sure I haven&#8217;t missed anything, but at this rate I&#8217;m expecting to be able to land the epic-refactor branch on trunk this weekend, after five and a half months.</p>
<p>Then I&#8217;m going to write a tool to convert old config files and we can think about putting out a 0.90 beta release. Exciting stuff!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/01/21/final-approach-for-terminator-epic-refactor/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Terminator 0.90 progress</title>
		<link>http://www.tenshu.net/archives/2010/01/19/terminator-0-90-progress/</link>
		<comments>http://www.tenshu.net/archives/2010/01/19/terminator-0-90-progress/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 10:08:14 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=378</guid>
		<description><![CDATA[Further to my previous post I thought I&#8217;d post a quick update about how things are progressing. I mentioned in my previous post that I knew of several things that were not yet working in the Epic Refactor branch:

-e and -x command line options
all forms of drag &#38; drop
directional navigation
some keyboard shortcuts

I&#8217;m pleased to say [...]]]></description>
			<content:encoded><![CDATA[<p>Further to my previous post I thought I&#8217;d post a quick update about how things are progressing. I mentioned in my previous post that I knew of several things that were not yet working in the Epic Refactor branch:</p>
<ul>
<li>-e and -x command line options</li>
<li>all forms of drag &amp; drop</li>
<li>directional navigation</li>
<li>some keyboard shortcuts</li>
</ul>
<p>I&#8217;m pleased to say that the first two of these are now taken care of, but the latter two are still to be done. I&#8217;m less pleased to say that I haven&#8217;t had much external feedback about this branch yet, but I suspect that most people who might be interested probably don&#8217;t read my blog ;)</p>
<p>So if you know people who like Terminator and enjoy testing things out, all they need to do is:</p>
<pre>bzr branch lp:~cmsj/terminator/epic-refactor
cd epic-refactor
./terminator
</pre>
<p>and give some feedback!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/01/19/terminator-0-90-progress/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Testing Terminator 0.90</title>
		<link>http://www.tenshu.net/archives/2010/01/05/testing-terminator-0-90/</link>
		<comments>http://www.tenshu.net/archives/2010/01/05/testing-terminator-0-90/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 13:12:40 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>
		<category><![CDATA[Ubuntu]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=375</guid>
		<description><![CDATA[You might have seen my recent posts about the epic refactoring that has been going on in the Terminator codebase for the last few months.
I think it&#8217;s finally time that we get some more eyeballs on it, mainly so I can check that I haven&#8217;t massively screwed something up. I know there is lots of [...]]]></description>
			<content:encoded><![CDATA[<p>You might have seen my recent posts about the epic refactoring that has been going on in the Terminator codebase for the last few months.</p>
<p>I think it&#8217;s finally time that we get some more eyeballs on it, mainly so I can check that I haven&#8217;t massively screwed something up. I know there is lots of missing functionality right now, and probably a bunch of subtle bugs, but I could use your help quantifying exactly what these are!</p>
<p>If you&#8217;re inclined to help, please branch<em> lp:~cmsj/terminator/epic-refactor</em>, cd into it and run <em>./terminator</em>, then use it like you always would and file bugs, preferably indicating clearly in the bug that you&#8217;re using this branch and not trunk (maybe tag the bug &#8216;<strong>epicrefactor</strong>&#8216;).</p>
<p>Things I know are broken right now:</p>
<ul>
<li>-e and -x command line options</li>
<li>all forms of drag &amp; drop</li>
<li>directional navigation</li>
<li>some keyboard shortcuts</li>
</ul>
<p>Things I know are missing because they&#8217;re not coming back:</p>
<ul>
<li>Extreme tabs mode (sorry, it&#8217;s just too insane to support)</li>
<li>GNOME Terminal profile reading (I&#8217;m trying to simplify our crazy config system and dropping GConf is a good way to achieve that)</li>
<li>Config file reading. At some point I&#8217;ll write something that migrates old Terminator configs to the new format, but for now you&#8217;ll have to live without your old config file. The new one isn&#8217;t documented yet either, but it is a whole bunch better!</li>
</ul>
<p>Now would also be a great time to start writing plugins for Terminator and telling me about them. I&#8217;m happy to ship good plugins, but more importantly I want feedback about the weaknesses/strengths of our plugin system. Right now you can only hook into URL mangling and the terminal context menu, but the latter of those gives you pretty serious flexibility I think. Obviously one massive weakness is a lack of documentation about the plugin API, but I&#8217;ll get to that, I promise!</p>
<p>So there we have it, another step along the way to me being able to merge this branch into trunk and put out a real release of 0.90 and then eventually 1.0!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2010/01/05/testing-terminator-0-90/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python wanderings, part two</title>
		<link>http://www.tenshu.net/archives/2009/12/31/python-wanderings-part-two/</link>
		<comments>http://www.tenshu.net/archives/2009/12/31/python-wanderings-part-two/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 23:42:08 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=370</guid>
		<description><![CDATA[2. Plugging it all in
Sometimes we get feature requests and merge proposals for features that are clearly useful for someone, but not appropriate for the general use cases. It&#8217;s always unfortunate to have to say no to these folks, but we have a slim menu UI and I&#8217;m wary of cluttering it with niche features. [...]]]></description>
			<content:encoded><![CDATA[<h2>2. Plugging it all in</h2>
<p>Sometimes we get feature requests and merge proposals for features that are clearly useful for someone, but not appropriate for the general use cases. It&#8217;s always unfortunate to have to say no to these folks, but we have a slim menu UI and I&#8217;m wary of cluttering it with niche features. Still, turning away legitimate users is something I don&#8217;t like doing, so for a while we&#8217;ve been considering how to fix this.</p>
<p>The obvious answer is that we should support plugins, and I&#8217;ve been working on such a system for my epic refactoring. This is a quick wander through some thoughts I&#8217;ve had.</p>
<p>I started out by googling for python plugin systems; One if the top hits was <a href="http://lucumr.pocoo.org/2006/7/3/python-plugin-system">this page</a> by Armin Ronacher . In it he demonstrates a plugin system in under 40 lines of Python. It&#8217;s simple and flexible, but there are some issues, like it makes doctest very sad.</p>
<p>I asked about this in #python and was politely informed that I was Doing It Wrong. I chatted for a while with the helpful residents and came away with a list of plugin frameworks to look at, namely twisted.plugin and zope.interface.</p>
<p>Pulling in external dependencies is a big deal for us &#8211; many of our users are on Ubuntu or similar desktops with lots of python packages already installed, but some are not using GNOME or a Linux desktop at all, so we have to be sure that we need a library before we depend on it.</p>
<p>After playing a little with both of the options I came to the conclusion that while they are both really well made and capable, they are far more formal than we need, and the added dependency issues continued to concern me.</p>
<p>I revisited Armin&#8217;s plugin system and removed the use of .__subclasses__() that was breaking doctest and offending #python instead having a list in each .py file which the plugin system extracts and treats any classes mentioned in that list as plugins. I also extended it to always instantiate the plugins and look for the plugin files in both the system directories and the user&#8217;s home directory.</p>
<p><a href="http://bazaar.launchpad.net/%7Ecmsj/%2Bjunk/terminator-epic-refactor/annotate/head%3A/terminatorlib/plugin.py">This plugin system</a> is currently hooked into two places in the branch, URL mangling and the context menu. This allows plugins to add support for new URL types (e.g. we just added support for Launchpad code URLs like lp:~cmsj/+junk/terminator-epic-refactor), and insert new options into the context menu. I&#8217;m not sure if we need to go further, but if you would like to hook into other parts let me know &#8211; it&#8217;s pretty easy to arrange now :)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2009/12/31/python-wanderings-part-two/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Python wanderings, part one</title>
		<link>http://www.tenshu.net/archives/2009/12/23/python-wanderings-part-one/</link>
		<comments>http://www.tenshu.net/archives/2009/12/23/python-wanderings-part-one/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 09:08:22 +0000</pubDate>
		<dc:creator>cmsj</dc:creator>
				<category><![CDATA[FOSS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Techie]]></category>
		<category><![CDATA[Terminator]]></category>

		<guid isPermaLink="false">http://www.tenshu.net/?p=360</guid>
		<description><![CDATA[As mentioned in my earlier post about refactoring Terminator, I want to talk about some of the things I&#8217;ve learned about Python and programming in the last few months. If I were you I wouldn&#8217;t place any great significance in anything I&#8217;m about to say &#8211; after all I&#8217;m a rank amateur in the field [...]]]></description>
			<content:encoded><![CDATA[<p>As mentioned in my earlier post about refactoring Terminator, I want to talk about some of the things I&#8217;ve learned about Python and programming in the last few months. If I were you I wouldn&#8217;t place any great significance in anything I&#8217;m about to say &#8211; after all I&#8217;m a rank amateur in the field of programming.</p>
<p>This is going to be a multi-part post so I at least get something out there, rather than leaving it to rot forever in my drafts folder.</p>
<h2>1. Solving global warming^W variables</h2>
<p>I have objects that represent terminal widgets, objects that represent widgets that contain terminals, objects that contain configuration, and one master object that functions as the brains of the operation.</p>
<p>Inevitably these objects need to know about each other, but how to achieve that? The brain object is simply called &#8216;Terminator&#8217; and almost every other part of the system needs to know about it, same with the config object, and Terminator needs to know about all of the terminal objects, etc. The dependencies are all over the place and one aim of the re-factor was to separate all these parts out and decouple them, but ultimately I was never going to get away from different objects needing to know about each other.</p>
<p>So how to go about it? As far as I know the options are:</p>
<ul>
<li>pass around object references (every time you create something, pass it your references to all the bits it needs)
<ul>
<li>Pros: no hacks or tricks involved</li>
<li>Cons: makes every __init__() more complicated, means passing references that an object doesn&#8217;t need other than to pass to its children.</li>
</ul>
</li>
<li>use global variables
<ul>
<li>Pros: they&#8217;re global</li>
<li>Cons: everyone seems to hate global variables, perhaps because it&#8217;s an implicit dependency not an explicit one, or because of potential namespace collisions, or maybe other reasons.</li>
</ul>
</li>
<li>use singletons
<ul>
<li>Pros: explicit dependency</li>
<li>Cons: often seems to involve hackery to get the singleton object reference</li>
</ul>
</li>
</ul>
<p>In my searching around I came across a fourth option that somewhat relates to singletons&#8230; the Borg pattern.</p>
<p>This is a very simple idea &#8211; it&#8217;s a class that always instantiates to the same thing. You don&#8217;t need a factory or function or something that gives you a reference to the singleton, you just instantiate a class and it&#8217;s the same as all of the others you&#8217;ve instantiated of the same class.</p>
<p>Best of all, the Borg pattern is incredibly simple in Python. Like, really simple. Don&#8217;t believe me? Click <a href="http://code.activestate.com/recipes/66531/">here</a>. Yep, four lines of code. Technically it&#8217;s probably a bit ugly, but the resulting code feels very clean.</p>
<p>So now I have the Borg pattern in use for the main class, a class that provides all the configuration, a class that discovers plugins and lets them be referenced, and a fairly new class I&#8217;m experimenting with that acts as a factory for all of my classes, as a way to break any possibility of circular module dependencies.</p>
<p>Reality has to bite though, the Borg isn&#8217;t a panacea; One has to be very careful about how one creates Borg objects. I chose to create a base class called Borg which Terminator, Config, Factory and PluginRegistry all derive from, but this turns out to have been a very short sighted decision to abstract out the common 4 lines. It wasn&#8217;t until I started building Config to have functions that allow it to be accessed as a dict that I realised all of my Terminator, Config, Factory and PluginRegistry instances were the same thing as opposed to each type being distinct. It&#8217;s also terrifyingly important that the subclasses of Borg not use class attributes. Any attributes defined by these classes *must* be instantiated as None so they are instance variables, and *after* you&#8217;ve called Borg.__init__(self) in your own __init__() you can then set up your attributes however you want because they are then part of the shared state.</p>
<p>On the whole I am happy with the Borg pattern. I&#8217;ve written test code to ensure that all of the assumptions I explicitly made are guaranteed, and all of the implicit assumptions I&#8217;ve discovered I made are also safe. Nonetheless, it&#8217;s not a completely clean solution and I find myself wishing it was somehow a primitive of the language.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.tenshu.net/archives/2009/12/23/python-wanderings-part-one/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
