<?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>The Troll-Range &#187; Python</title>
	<atom:link href="http://blog.trollgod.org.uk/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.trollgod.org.uk</link>
	<description>Ghworg&#039;s wibblings and geek projects.</description>
	<lastBuildDate>Mon, 26 Apr 2010 19:31:11 +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>Poor mans offsite backup</title>
		<link>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/</link>
		<comments>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/#comments</comments>
		<pubDate>Sat, 02 May 2009 07:00:34 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[gmail]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=192</guid>
		<description><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail. Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p> <p>This is the script I used to send the <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/">Poor mans offsite backup</a></span>]]></description>
			<content:encoded><![CDATA[<p>Before I got some proper offsite backup space* I used to make tarballs of files and dump them in my gmail.  Not the most elegant solution but it worked and is free (I know about gmailfs, but I could never get it to work reliably).</p>
<p>This is the script I used to send the files:</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span><br />
<span class="kw1">import</span> <span class="kw3">getpass</span><br />
<span class="kw1">import</span> <span class="kw3">optparse</span><br />
<span class="kw1">import</span> <span class="kw3">smtplib</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p><span class="kw1">from</span> <span class="kw3">email</span> <span class="kw1">import</span> Encoders<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEBase</span> <span class="kw1">import</span> MIMEBase<br />
<span class="kw1">from</span> <span class="kw3">email</span>.<span class="me1">MIMEMultipart</span> <span class="kw1">import</span> MIMEMultipart</p>
<p>
opts = <span class="kw3">optparse</span>.<span class="me1">OptionParser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-u&#8217;</span>, <span class="st0">&#8216;&#8211;username&#8217;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-p&#8217;</span>, <span class="st0">&#8216;&#8211;password&#8217;</span><span class="br0">&#41;</span><br />
<span class="br0">&#40;</span>options, args<span class="br0">&#41;</span> = opts.<span class="me1">parse_args</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span>args<span class="br0">&#41;</span> &lt; <span class="nu0">1</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&quot;Usage: send_file_to_gmail.py [-u user] [-p pass] filename&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span></p>
<p><span class="kw1">if</span> options.<span class="me1">username</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> = <span class="kw2">raw_input</span><span class="br0">&#40;</span><span class="st0">&quot;Username: &quot;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">password</span> == <span class="kw2">None</span>:<br />
&nbsp; &nbsp; options.<span class="me1">password</span> = <span class="kw3">getpass</span>.<span class="kw3">getpass</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">if</span> options.<span class="me1">username</span><span class="br0">&#91;</span><span class="kw2">len</span><span class="br0">&#40;</span>options.<span class="me1">username</span><span class="br0">&#41;</span><span class="nu0">-10</span>:<span class="br0">&#93;</span> != <span class="st0">&quot;@gmail.com&quot;</span>:<br />
&nbsp; &nbsp; options.<span class="me1">username</span> += <span class="st0">&quot;@gmail.com&quot;</span></p>
<p>
msg = MIMEMultipart<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;Subject&#8217;</span><span class="br0">&#93;</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;From&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span><br />
msg<span class="br0">&#91;</span><span class="st0">&#8216;To&#8217;</span><span class="br0">&#93;</span> = options.<span class="me1">username</span></p>
<p>msg.<span class="me1">preamble</span> = <span class="st0">&quot;Backup of %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
msg.<span class="me1">epilogue</span> = <span class="st0">&quot; &quot;</span></p>
<p>fp = <span class="kw2">open</span><span class="br0">&#40;</span>args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, <span class="st0">&quot;rb&quot;</span><span class="br0">&#41;</span><br />
atfile = MIMEBase<span class="br0">&#40;</span><span class="st0">&quot;application&quot;</span>, <span class="st0">&quot;octet-stream&quot;</span><span class="br0">&#41;</span><br />
atfile.<span class="me1">set_payload</span><span class="br0">&#40;</span>fp.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
fp.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
Encoders.<span class="me1">encode_base64</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span><br />
atfile.<span class="me1">add_header</span><span class="br0">&#40;</span><span class="st0">&quot;Content-Disposition&quot;</span>, <span class="st0">&quot;attachment&quot;</span>, filename=args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
msg.<span class="me1">attach</span><span class="br0">&#40;</span>atfile<span class="br0">&#41;</span></p>
<p>s = <span class="kw3">smtplib</span>.<span class="me1">SMTP</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="co1">#s.connect(&quot;localhost&quot;, &quot;8025&quot;)</span><br />
s.<span class="me1">connect</span><span class="br0">&#40;</span><span class="st0">&quot;smtp.gmail.com&quot;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">starttls</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">ehlo</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
s.<span class="me1">login</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">password</span><span class="br0">&#41;</span><br />
<span class="kw1">print</span> <span class="st0">&quot;Sending %s&quot;</span> % args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><br />
s.<span class="me1">sendmail</span><span class="br0">&#40;</span>options.<span class="me1">username</span>, options.<span class="me1">username</span>, msg.<span class="me1">as_string</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
s.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp;</div>
<p>The above code is made available under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a> license.</p>
<p>* While I am writing this the Dreamhost backup space I use has been down for about two weeks (it came back briefly a couple of days ago but is back down again now).  I can&#8217;t complain too much as it is a free extra they throw in with the hosting package but I may have to restart my gmail sending if this keeps up.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/05/poor-mans-offsite-backup/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Convert files to UTF-8</title>
		<link>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/#comments</comments>
		<pubDate>Thu, 16 Apr 2009 05:00:54 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[conversion]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[utf8]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=178</guid>
		<description><![CDATA[<p>I occasionally come across text files with weird squiggles or numbers in them were there should be characters. Usually it&#8217;s accented characters, but in extreme cases I&#8217;ve seen it happen with speech marks.</p> <p>The problem of course is that the files are not ASCII, and text files don&#8217;t store what character set they were <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/">Convert files to UTF-8</a></span>]]></description>
			<content:encoded><![CDATA[<p>I occasionally come across text files with weird squiggles or numbers in them were there should be characters.  Usually it&#8217;s accented characters, but in extreme cases I&#8217;ve seen it happen with speech marks.</p>
<p>The problem of course is that the files are not ASCII, and text files don&#8217;t store what character set they were created with.  So if the set my system happens to use doesn&#8217;t match the one the file uses then the result is screwed up letters.</p>
<p>To solve this I created a little python script that converts the file into using the UTF-8 character set as that is nice and universal.  You can specify what codec the input is in with the -c option, if you don&#8217;t bother then it assumes the Windows 1252 codepage as that is usually what it is in my experience.  There is also a force option for when the conversion comes across characters that don&#8217;t match the input codec but you want it to convert anyway.</p>
<p>I thought about making it autodetect the codec of the input file, but it is a lot of work for little benefit.  The current code works in 99% of cases for me.</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="co1">#!/usr/bin/env python</span></p>
<p><span class="kw1">import</span> <span class="kw3">codecs</span><br />
<span class="kw1">import</span> <span class="kw3">optparse</span><br />
<span class="kw1">import</span> <span class="kw3">sys</span></p>
<p><span class="kw1">if</span> <span class="kw2">len</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">argv</span><span class="br0">&#41;</span> &lt; <span class="nu0">2</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&#8216;convert_cp1252_to_UTF-8.py [-f] $filename&#8217;</span><br />
&nbsp; &nbsp; <span class="kw3">sys</span>.<span class="me1">exit</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span></p>
<p>opts = <span class="kw3">optparse</span>.<span class="me1">OptionParser</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="co1"># &#8216;help&#8217;, &#8216;config=&#8217;, &#8216;logfile=&#8217;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-f&#8217;</span>, <span class="st0">&#8216;&#8211;force&#8217;</span>, action=<span class="st0">&#8216;store_true&#8217;</span><span class="br0">&#41;</span><br />
opts.<span class="me1">add_option</span><span class="br0">&#40;</span><span class="st0">&#8216;-c&#8217;</span>, <span class="st0">&#8216;&#8211;codec&#8217;</span>, default=<span class="st0">&#8216;cp1252&#8242;</span><span class="br0">&#41;</span><br />
<span class="br0">&#40;</span>parsedOpts, args<span class="br0">&#41;</span> = opts.<span class="me1">parse_args</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
filename = args<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span></p>
<p><span class="kw1">try</span>:<br />
&nbsp; &nbsp; <span class="kw1">if</span> parsedOpts.<span class="me1">force</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; textfile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename, <span class="st0">&#8216;r&#8217;</span>, encoding=parsedOpts.<span class="me1">codec</span>, errors=<span class="st0">&#8216;ignore&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; textfile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename, <span class="st0">&#8216;r&#8217;</span>, encoding=parsedOpts.<span class="me1">codec</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; utffile = <span class="kw3">codecs</span>.<span class="kw2">open</span><span class="br0">&#40;</span>filename+<span class="st0">&#8216;.utf-8&#8242;</span>, <span class="st0">&#8216;w&#8217;</span>, encoding=<span class="st0">&#8216;utf-8&#8242;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; utffile.<span class="me1">write</span><span class="br0">&#40;</span>textfile.<span class="me1">read</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
<span class="kw1">except</span>:<br />
&nbsp; &nbsp; <span class="kw1">print</span> <span class="st0">&#8216;Error converting to UTF-8, source file probably doesn&#8217;</span>t use cp1252<span class="st0">&#8216;<br />
</span></div>
<p>The above code is made available under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT</a> license.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/convert-files-to-utf-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Build numbers in interpreted code</title>
		<link>http://blog.trollgod.org.uk/2009/04/build-numbers-in-interpreted-code/</link>
		<comments>http://blog.trollgod.org.uk/2009/04/build-numbers-in-interpreted-code/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 06:00:20 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[versioncontrol]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=147</guid>
		<description><![CDATA[<p>When I write a program I like to include a build number in the version. Usually I go version.revision.build. The version only ever gets bumped for things that are practically a complete rewrite, and sometimes not even then. The revision gets bumped for new features or major bug fixes and the build gets bumped <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/04/build-numbers-in-interpreted-code/">Build numbers in interpreted code</a></span>]]></description>
			<content:encoded><![CDATA[<p>When I write a program I like to include a build number in the version.  Usually I go <strong>version.revision.build</strong>.  The version only ever gets bumped for things that are practically a complete rewrite, and sometimes not even then.  The revision gets bumped for new features or major bug fixes and the build gets bumped for every compile.</p>
<p>This gives the huge of advantage of being able to identify the exact time a particular version of a program was created and thus make bug finding easier.</p>
<p>For compiled code this works really well, I just have the build process increment the number somehow.  For interpreted code, such as python, however there is no build process.  So how do I make sure the build number gets incremented every time?  There is no way I would remember to increment it manually.</p>
<p>When I was using subversion I hacked something together using <em>$LastChangedRevision$</em>, so the build number was based on the most recent svn commit number.  It worked well enough and I was happy.</p>
<p>Now however I&#8217;m switching to git, which doesn&#8217;t have keywords like CVS and Subversion so I&#8217;m a bit stumped.  I tried hacking a script that auto-increments a number then runs a <em>git commit</em>, but not only is it logically flawed, but it relies on me remembering to run it rather than direct git commands which is never going to be reliable.</p>
<p>Maybe I could do something with the current date, but again that would rely on me running something.  Probably repo hooks are the answer somehow but I&#8217;ve no idea how.  The build no. itself needs to be stored in git so as to sync between computers.  Can a git repo hook update a file then commit that update back to itself automatically (without an infinite recursion destroying the repo)?</p>
<p>Update (2009-04-05):  I&#8217;ve worked out how to generate an auto-incrementing number via git hooks.  Use the following script as a pre-commit hook (save as .git/hooks/pre-commit).  It&#8217;s setup for python but it could easily be adapted for whatever language you need.</p>
<div class="dean_ch" style="white-space: nowrap;">
<span class="re3">#!/bin/bash</span><br />
<span class="re3">#</span><br />
<span class="re3"># Called by git-commit with no arguments. &nbsp;The hook should</span><br />
<span class="re3"># <span class="kw3">exit</span> with non-zero status after issuing an appropriate message if</span><br />
<span class="re3"># it wants to stop the commit.</span><br />
<span class="re3">#</span><br />
<span class="re3"># This script will automatically increment the __revision__ number in</span><br />
<span class="re3"># the <span class="kw2">file</span> version.py on every git commit.</span></p>
<p><span class="re2">f=</span><span class="st0">&quot;$GIT_DIR/../version.py&quot;</span></p>
<p><span class="re2">REVISION=</span>$<span class="br0">&#40;</span><span class="kw2">grep</span> <span class="st0">&#8216;^__revision__&#8217;</span> <span class="re1">$f</span> | <span class="kw2">sed</span> <span class="st0">&#8216;s/^__revision__ = //&#8217;</span><span class="br0">&#41;</span><br />
<span class="re3">#echo </span><span class="st0">&quot;Current revision = $REVISION&quot;</span><br />
<span class="kw3">let</span> <span class="re2">REVISION=</span><span class="re1">$REVISION</span><span class="nu0">+1</span><br />
<span class="re3">#echo </span><span class="st0">&quot;New revision = $REVISION&quot;</span><br />
<span class="kw2">sed</span> -r <span class="st0">&quot;s/^(__revision__ = )([0-9]+)$/<span class="es0">\1</span>$REVISION/&quot;</span> &lt; <span class="re1">$f</span> &gt; <span class="re1">$f</span>.new<br />
<span class="kw2">mv</span> <span class="re1">$f</span>.new <span class="re1">$f</span><br />
git add <span class="re1">$f</span><br />
&nbsp;</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/04/build-numbers-in-interpreted-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Twitter to XMPP (Jabber)</title>
		<link>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/</link>
		<comments>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 21:23:50 +0000</pubDate>
		<dc:creator>Ghworg</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[project]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[xmpp]]></category>

		<guid isPermaLink="false">http://blog.trollgod.org.uk/?p=118</guid>
		<description><![CDATA[<p>The other day I noticed that irssi (the IRC client I use) had a XMPP plugin. It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p> <p>For identi.ca this was a doddle, since laconica supports XMPP natively. Twitter however <span style="color:#777"> . . . &#8594; Read More: <a href="http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/">Twitter to XMPP (Jabber)</a></span>]]></description>
			<content:encoded><![CDATA[<p>The other day I noticed that <a href="http://irssi.org/">irssi</a> (the <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">IRC</a> client I use) had a <a href="http://cybione.org/~irssi-xmpp/">XMPP plugin</a>.  It occurred to me that since I&#8217;m on IRC a lot it would be really cool to pull microblog feeds into irssi via this plugin.</p>
<p>For <a href="http://identi.ca/ghworg">identi.ca</a> this was a doddle, since <a href="http://laconi.ca/">laconica</a> supports <a href="http://en.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol">XMPP</a> natively.  <a href="http://twitter.com/Ghworg">Twitter</a> however was a problem.  I believe twitter used to support XMPP but they pulled that feature for who knows what reason.</p>
<p>There are a couple of apps that will provided a twitter->XMPP gateway for you.  I looked at <a href="http://dustin.github.com/twitterspy/">twitterspy</a>, but it sounded like a pain to install.  So at first I tried <a href="https://www.tweet.im/">tweet.im</a>, which worked after a fashion.  It got the tweets into irssi, but it did it in some weird way so that irssi didn&#8217;t realise new messages had come in and hence it didn&#8217;t indicate there was activity when I was in a different irssi window.</p>
<p>At this point the little voice in my head that is the bane of my life started saying &#8220;You know, you could probably write your own gateway app.  How hard could it be?&#8221;.  Like a fool I listened to this voice, but for once it didn&#8217;t turn out disastrously.  A few hours later I had a functioning (one-way) twitter->XMPP app, written in python.</p>
<p>I&#8217;ve since learned that twitterspy has been rewritten in python and would have been a doddle to install.  Not only that but there is a public instance of it I could have used.  Still, I&#8217;m not immune to <a href="http://en.wikipedia.org/wiki/Not_Invented_Here">NIH</a> syndrome and having my own app to do it is nice.  If you want a twitter->XMPP gateway of your own though I suggest you try <a href="http://dustin.github.com/twitterspy/">twitterspy</a> first as it is much more capable (and mature) than my noddy little script.</p>
<p>But if you are interested, and because I like to boast about my tiny little achievements, here is twixm (I&#8217;ll give it its own page when I get round to it, but till then it is going to live in this blog post).</p>
<div class="dean_ch" style="white-space: nowrap;">
<p><span class="co1">#!/usr/bin/python -u</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is free software: you can redistribute it and/or modify</span><br />
<span class="co1"># it under the terms of the GNU General Public License as published by</span><br />
<span class="co1"># the Free Software Foundation, either version 2 of the License, or</span><br />
<span class="co1"># (at your option) any later version.</span><br />
<span class="co1">#</span><br />
<span class="co1"># This program is distributed in the hope that it will be useful,</span><br />
<span class="co1"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br />
<span class="co1"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. &nbsp;See the</span><br />
<span class="co1"># GNU General Public License for more details.</span><br />
<span class="co1">#</span><br />
<span class="co1"># You should have received a copy of the GNU General Public License</span><br />
<span class="co1"># along with this program. &nbsp;If not, see &lt;http://www.gnu.org/licenses/&gt;.</span><br />
<span class="co1"># </span></p>
<p>__author__ = <span class="st0">&quot;Ghworg&quot;</span><br />
__version__ = <span class="st0">&quot;1.0&quot;</span><br />
__description__ = <span class="st0">&quot;Twitter to XMPP gateway&quot;</span></p>
<p>
<span class="kw1">import</span> <span class="kw3">logging</span>, <span class="kw3">os</span>, <span class="kw3">signal</span>, <span class="kw3">sys</span>, <span class="kw3">threading</span>, <span class="kw3">time</span>, <span class="kw3">urllib</span></p>
<p><span class="kw1">import</span> simplejson</p>
<p><span class="kw1">try</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> iniparse.<span class="me1">compat</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span><br />
<span class="kw1">except</span> <span class="kw2">ImportError</span>:<br />
&nbsp; &nbsp; <span class="kw1">from</span> <span class="kw3">ConfigParser</span> <span class="kw1">import</span> <span class="kw3">ConfigParser</span></p>
<p><span class="kw1">from</span> pyxmpp.<span class="me1">jid</span> <span class="kw1">import</span> JID<br />
<span class="kw1">from</span> pyxmpp.<span class="me1">jabber</span>.<span class="me1">simple</span> <span class="kw1">import</span> send_message</p>
<p>
<span class="kw1">class</span> WebApiOpener<span class="br0">&#40;</span><span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;<br />
&nbsp; &nbsp; Provides a way for HTTP Basic authentication to take place without<br />
&nbsp; &nbsp; prompting the user for a username and password like FancyURLopener<br />
&nbsp; &nbsp; would.<br />
&nbsp; &nbsp; &quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>, username, password<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">urllib</span>.<span class="me1">FancyURLopener</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span>,<span class="br0">&#123;</span><span class="br0">&#125;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">username</span> = username<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">self</span>.<span class="me1">password</span> = password<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> prompt_user_passwd<span class="br0">&#40;</span><span class="kw2">self</span>, host, realm<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle Basic Auth automatically.&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span><span class="kw2">self</span>.<span class="me1">username</span>, <span class="kw2">self</span>.<span class="me1">password</span><span class="br0">&#41;</span></p>
<p>
<span class="kw1">class</span> CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="kw3">ConfigParser</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Case Sensitive version of ConfigParser&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">def</span> <span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">ConfigParser</span>.<span class="kw4">__init__</span><span class="br0">&#40;</span><span class="kw2">self</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> optionxform<span class="br0">&#40;</span><span class="kw2">self</span>, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Make keys case-sensitive&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">str</span><span class="br0">&#40;</span>option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">def</span> getAndType<span class="br0">&#40;</span><span class="kw2">self</span>, section, option<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Try to guess variable type and convert to type before returning&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; rawVal = <span class="kw2">self</span>.<span class="me1">get</span><span class="br0">&#40;</span>section, option<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> c <span class="kw1">in</span> rawVal:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> c.<span class="me1">isdigit</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isInt = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> c != <span class="st0">&#8216;.&#8217;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isFloat = <span class="kw2">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> isInt:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">int</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elif</span> isFloat:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">float</span><span class="br0">&#40;</span>rawVal<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> rawVal</p>
<p>
<span class="kw1">def</span> msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Send a message to Jabber (XMPP)&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> jid.<span class="kw3">resource</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; jid = JID<span class="br0">&#40;</span>jid.<span class="me1">node</span>, jid.<span class="me1">domain</span>, <span class="st0">&#8216;send_message&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; recpt = JID<span class="br0">&#40;</span>config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Sending to XMPP &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; send_message<span class="br0">&#40;</span>jid, config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span>, recpt, msg<span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> getTweets<span class="br0">&#40;</span><span class="kw3">site</span>, maxTweets=<span class="nu0">1</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Read in a list of tweets made since the last check&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">in</span> cache:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?since_id=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; url = <span class="st0">&#8216;%s?count=%d&#8217;</span> % <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>, maxTweets<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; opener = WebApiOpener<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span class="kw1">try</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Requesting %s&#8217;</span> % url<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; webPage = opener.<span class="kw2">open</span><span class="br0">&#40;</span>url<span class="br0">&#41;</span> &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; jsonData = simplejson.<span class="me1">load</span><span class="br0">&#40;</span>webPage<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="st0">&#8216;error&#8217;</span> <span class="kw1">in</span> jsonData<span class="br0">&#41;</span> <span class="kw1">and</span> <span class="br0">&#40;</span>jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span> != <span class="st0">&#8221;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Error from server %s: %s&#8217;</span> % <span class="br0">&#40;</span>url, jsonData<span class="br0">&#91;</span><span class="st0">&#8216;error&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jsonData = <span class="kw2">None</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">IOError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">except</span> <span class="kw2">ValueError</span>, e:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span>e<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">error</span><span class="br0">&#40;</span><span class="st0">&#8216;URL = %s&#8217;</span> % src<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; maxID = <span class="nu0">0</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> tweet <span class="kw1">in</span> jsonData:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span> &gt; maxID:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;id&#8217;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msg = <span class="st0">&#8216;%s (%s): %s&#8217;</span> % <span class="br0">&#40;</span>tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;user&#8217;</span><span class="br0">&#93;</span><span class="br0">&#91;</span>u<span class="st0">&#8216;screen_name&#8217;</span><span class="br0">&#93;</span>, <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, tweet<span class="br0">&#91;</span>u<span class="st0">&#8216;text&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Read tweet &nbsp;%s&#8217;</span> % msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; msgToXMPP<span class="br0">&#40;</span>msg<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">return</span> maxID</p>
<p><span class="kw1">def</span> run<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Thread&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="kw2">True</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; startSignal.<span class="me1">clear</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; maxID = getTweets<span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="kw1">not</span> <span class="kw1">in</span> cache<span class="br0">&#41;</span> <span class="kw1">or</span> <span class="br0">&#40;</span>maxID &gt; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cache<span class="br0">&#91;</span><span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#93;</span> = maxID</p>
<p><span class="kw1">def</span> readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Load config settings&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; config = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; cfgfile = <span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">join</span><span class="br0">&#40;</span><span class="kw3">os</span>.<span class="me1">path</span>.<span class="me1">expanduser</span><span class="br0">&#40;</span><span class="st0">&#8216;~&#8217;</span><span class="br0">&#41;</span>, <span class="st0">&#8216;.twixmrc&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span> = CaseSensitiveConfigParser<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">parser</span>.<span class="me1">read</span><span class="br0">&#40;</span>cfgfile<span class="br0">&#41;</span><br />
&nbsp; &nbsp; settings = <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> section <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">sections</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;XMPP&#8217;</span> == section:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">for</span> optname <span class="kw1">in</span> <span class="kw3">parser</span>.<span class="me1">options</span><span class="br0">&#40;</span>section<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span>optname<span class="br0">&#93;</span> = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, optname<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteName = section<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUrl = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;URL&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; siteUser = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Username&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sitePass = <span class="kw3">parser</span>.<span class="me1">getAndType</span><span class="br0">&#40;</span>section, <span class="st0">&#8216;Password&#8217;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">site</span> = <span class="br0">&#40;</span>siteName, siteUrl, siteUser, sitePass<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="st0">&#8216;site&#8217;</span> <span class="kw1">not</span> <span class="kw1">in</span> config:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span> = <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>.<span class="me1">append</span><span class="br0">&#40;</span><span class="kw3">site</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span> = <span class="nu0">60.0</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="co1"># !!! Check for missing config settings and bail out</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP ID = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;jid&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;XMPP Pass = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;XMPPpass&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Cycle Time = %s&#8217;</span> % config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="kw3">site</span> <span class="kw1">in</span> config<span class="br0">&#91;</span><span class="st0">&#8216;site&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;Site: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>URL: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>User: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">debug</span><span class="br0">&#40;</span><span class="st0">&#8216;<span class="es0">\t</span>Pass: %s&#8217;</span> % <span class="kw3">site</span><span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="kw1">return</span> config<br />
&nbsp; &nbsp; &nbsp; &nbsp; </p>
<p><span class="kw1">def</span> setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Setup python logging to stdout&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; log = <span class="kw3">logging</span>.<span class="me1">getLogger</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; logformat = <span class="st0">&#8216;%(asctime)s %(levelname)s %(message)s&#8217;</span><br />
&nbsp; &nbsp; dateformat = <span class="st0">&#8216;%Y-%m-%d %H:%M:%S&#8217;</span><br />
&nbsp; &nbsp; frmttr = <span class="kw3">logging</span>.<span class="me1">Formatter</span><span class="br0">&#40;</span>logformat, dateformat<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#if options.logfile:</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr = logging.FileHandler(options.logfile)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;fhdlr.setFormatter(frmttr)</span><br />
&nbsp; &nbsp; <span class="co1"># &nbsp; &nbsp;log.addHandler(fhdlr)</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw3">sys</span>.<span class="me1">stdin</span>.<span class="me1">isatty</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr = <span class="kw3">logging</span>.<span class="me1">StreamHandler</span><span class="br0">&#40;</span><span class="kw3">sys</span>.<span class="me1">stdout</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; shdlr.<span class="me1">setFormatter</span><span class="br0">&#40;</span>frmttr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; log.<span class="me1">addHandler</span><span class="br0">&#40;</span>shdlr<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">#log.setLevel(logging.DEBUG)</span><br />
&nbsp; &nbsp; log.<span class="me1">setLevel</span><span class="br0">&#40;</span><span class="kw3">logging</span>.<span class="me1">INFO</span><span class="br0">&#41;</span></p>
<p><span class="kw1">def</span> handler<span class="br0">&#40;</span>signum, frame<span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; <span class="st0">&quot;&quot;</span><span class="st0">&quot;Handle various termination signals gracefully&quot;</span><span class="st0">&quot;&quot;</span><br />
&nbsp; &nbsp; <span class="kw3">logging</span>.<span class="me1">warning</span><span class="br0">&#40;</span><span class="st0">&#8216;Signal handler called with signal %d&#8217;</span> % signum<span class="br0">&#41;</span><br />
&nbsp; &nbsp; quitSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>
<span class="co1">###############################################################################</span><br />
<span class="co1"># Main</span><br />
<span class="co1">###############################################################################</span></p>
<p><span class="co1"># Set the signal handlers</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGTERM</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGQUIT</span>, handler<span class="br0">&#41;</span><br />
<span class="kw3">signal</span>.<span class="kw3">signal</span><span class="br0">&#40;</span><span class="kw3">signal</span>.<span class="me1">SIGINT</span>, handler<span class="br0">&#41;</span></p>
<p>setupLogging<span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>config = readConfig<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
cache = <span class="br0">&#123;</span><span class="br0">&#125;</span></p>
<p>
quitSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
startSignal = <span class="kw3">threading</span>.<span class="me1">Event</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p>runThread = <span class="kw3">threading</span>.<span class="me1">Thread</span><span class="br0">&#40;</span>target=run<span class="br0">&#41;</span><br />
runThread.<span class="me1">start</span><span class="br0">&#40;</span><span class="br0">&#41;</span></p>
<p><span class="kw1">while</span> <span class="kw2">False</span> == quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; startSignal.<span class="kw2">set</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; count = <span class="nu0">0.0</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> count &lt; config<span class="br0">&#91;</span><span class="st0">&#8216;cycleTime&#8217;</span><span class="br0">&#93;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; quitSignal.<span class="me1">wait</span><span class="br0">&#40;</span><span class="nu0">0.5</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; count += <span class="nu0">0.5</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> quitSignal.<span class="me1">isSet</span><span class="br0">&#40;</span><span class="br0">&#41;</span>:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><br />
<span class="kw3">logging</span>.<span class="me1">info</span><span class="br0">&#40;</span><span class="st0">&#8216;Exiting&#8217;</span><span class="br0">&#41;</span></p>
<p>&nbsp;</p></div>
<p>Update 2009-11-25:  I have created a page for <a href="/projects/twixm/">twixm</a> now.  Go there for the latest code and info.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.trollgod.org.uk/2009/03/twitter-to-xmpp-jabber/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
