<?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>toxicsoftware.com &#187; Python</title>
	<atom:link href="http://toxicsoftware.com/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://toxicsoftware.com</link>
	<description>RANDOMIZE USR 0</description>
	<lastBuildDate>Thu, 17 Dec 2009 15:12:37 +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>Webloc to Pinboard</title>
		<link>http://toxicsoftware.com/webloc-to-pinboard/</link>
		<comments>http://toxicsoftware.com/webloc-to-pinboard/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 14:34:40 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[hazel]]></category>
		<category><![CDATA[pinboard]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[url]]></category>
		<category><![CDATA[webloc]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/?p=445</guid>
		<description><![CDATA[If I want to keep a URL around for later I generally drag the URL from Safari&#8217;s URL bar onto the desktop. This creates an &#8220;internet clipping file&#8221; (with a .webloc file extension). These files are like little self contained bookmarks that, when double clicked open the linked webpage in Safari. Because they&#8217;re just ordinary [...]]]></description>
			<content:encoded><![CDATA[<p>If I want to keep a URL around for later I generally drag the URL from Safari&#8217;s URL bar onto the desktop. This creates an &#8220;internet clipping file&#8221; (with a .webloc file extension). These files are like little self contained bookmarks that, when double clicked open the linked webpage in Safari. Because they&#8217;re just ordinary files, you can manage them like any other file, store them in folders, copy them around, delete them, etc.</p>

<p>Eventually these clippings will get deleted or filed in a folder and forgotten. In the past I&#8217;ve written Spotlight importers to try and gather all these clippings and then export them in a format I could use in a bookmark manager application, such as WebNoteHappy. But most bookmark manager apps tend to be quite limited and I&#8217;ve found online services such as <a href="http://delicious.com">delicious</a>, <a href="http://instapaper.com">instapaper</a> and now <a href="http://pinboard.in">pinboard.in</a> to be far superior to any desktop application.</p>

<p>But getting from an internet clipping on my desktop to an entry in an online bookmark manager usually involves a lot of manual labour.</p>

<p>I&#8217;ve found a great solution using <a href="http://www.noodlesoft.com/hazel.php">Hazel</a> and a custom Python script. I have a Hazel rule that finds files with a &#8220;.webloc&#8221; file extension on my desktop. The rule then runs a single python script to add the URL to my pinboard.in account and then moves the file into the trash. Usually Hazel notices the clipping, adds it to pinboard.in and trashes the file within a couple of seconds.</p>

<div style="text-align:center;"><a href="http://www.flickr.com/photos/61285556@N00/4192151805" title="View 'Screen shot 2009-12-17 at 09.12.35' on Flickr.com"><img border="0" width="100" alt="Screen shot 2009-12-17 at 09.12.35" src="http://farm3.static.flickr.com/2495/4192151805_d5b0ce0737_t.jpg" height="77"/></a></div>

<p>The python script is where all the magic happens:</p>

<pre><code>#!/usr/bin/python

import sys
import urllib
import urllib2
import re
import subprocess
import Foundation
from Carbon import File, Files, Res

def infoForWebloc(inPath):
    theDisplayName = Foundation.NSFileManager.defaultManager().displayNameAtPath_(inPath)
    resNum = Res.FSOpenResourceFile(inPath, File.FSGetResourceForkName(), Files.fsRdPerm)
    Res.UseResFile(resNum)
    theResource = Res.Get1Resource('url ', 256)
    theURLFromResource = theResource.data
    Res.CloseResFile(resNum)
    theData = Foundation.NSData.dataWithContentsOfFile_(inPath)
    thePropertyList = Foundation.NSPropertyListSerialization.propertyListWithData_options_format_error_(theData, 0, None, None)
    theURLFromData = thePropertyList['URL'] 
    return theDisplayName, theURLFromResource

def getAccount(inServer):
    theArguments = ['security', 'find-internet-password', '-s', inServer, '-g']
    thePipe = subprocess.Popen(theArguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    theOutput = thePipe.stdout.read()
    theMatch = re.search(r'"acct"&lt;blob&gt;="(.+)"', theOutput)
    theUsername = theMatch.groups()[0]
    theOutput = thePipe.stderr.read()
    theMatch = re.match(r'^password: "(.+)"$', theOutput)
    thePassword = theMatch.groups()[0]
    return theUsername, thePassword

def upload(inURL, inDescription):
    password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
    top_level_url = "https://api.pinboard.in/v1"
    theUsername, thePassword = getAccount('api.pinboard.in')
    password_mgr.add_password(None, top_level_url, theUsername, thePassword)
    handler = urllib2.HTTPBasicAuthHandler(password_mgr)
    opener = urllib2.build_opener(handler)
    inURL = urllib.quote(inURL)
    inDescription = urllib.quote(inDescription)
    theURL = 'https://api.pinboard.in/v1/posts/add?url=%s&amp;shared=no&amp;replace=yes&amp;description=%s' % (inURL, inDescription)
    theResult = opener.open(theURL)

def main(args):
    for thePath in args:
        theDescription, theURL = infoForWebloc(thePath)
        upload(theURL, theDescription)

if __name__ == '__main__':
    main(sys.argv[1:])
</code></pre>

<p>This script reads the .webloc file to extract the URL (.webloc files store the URL in both the Carbon resource fork and in the data fork in a property list format, this script extracts the URL from both locations but only uses the URL from the resource fork.</p>

<p>Then script uploads the URL to pinboard.in via pinboard.in&#8217;s delicious style API. The script gets your pinboard.in username and password from your keychain. To add the username and password to your keychain you&#8217;ll want to run this little shell script.</p>

<pre><code>#!/bin/sh

HOST=api.pinboard.in
read -p "Username: " USERNAME
read -p "Password: " -s PASSWORD
security add-internet-password -U -r http -s "$HOST" -a "$USERNAME" -w "$PASSWORD"
</code></pre>

<p>You can download the Hazel rule <a href="http://toxicsoftware.com/wordpress/uploads/Desktop.hazelrules.zip">here</a>, but do remember to set up your pinboard.in keychain item before installing it.</p>

<p>Instead of using the entire desktop as a sort of a dropbox for URLs you could easily adapt the script and put it into a automator action or perhaps a system service.</p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/webloc-to-pinboard/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Making Mercurial use the Mac OS X Keychain</title>
		<link>http://toxicsoftware.com/hgkeychain/</link>
		<comments>http://toxicsoftware.com/hgkeychain/#comments</comments>
		<pubDate>Wed, 13 Feb 2008 17:54:10 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[hg]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[mercurial]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[rcs]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/hgkeychain/</guid>
		<description><![CDATA[I&#8217;ve taken the plunge and am in the middle of switching from Subversion to Mercurial for revision control. Subversion has served me relatively faithfully for many years (I&#8217;ve even championed/led the adoption of subversion at two companies I&#8217;ve worked for in the past) but some of the warts and shortcomings were beginning to annoy me [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve taken the plunge and am in the middle of switching from Subversion to Mercurial for revision control. Subversion has served me relatively faithfully for many years (I&#8217;ve even championed/led the adoption of subversion at two companies I&#8217;ve worked for in the past) but some of the warts and shortcomings were beginning to annoy me (. directories everywhere for example). Dave Dribin&#8217;s <a href="http://www.dribin.org/dave/blog/archives/2007/12/30/why_mercurial/">series of posts</a> about the Mercurial DVCS software piqued my interest and I was soon switching  repositories to hg.</p>

<p>One feature that  added recently that hg lacked was the ability to store repository passwords in the Mac OS X keychain. In fact mercurial lacks the ability to store a repository password anywhere other than in the url used to access the repository (i.e. http://user:password@example.com/path). I think this is a bit of security flaw. The password is stored as plain text within the repository config file (&#8216;.hg/hgrc&#8217;) file.</p>

<p>Fortunately Mercurial provides a simple interface for extension modules. After a little bit of hacking I was able to write an hg extension that stores and retrieves the password from the keychain. I&#8217;ve put the code online for anyone to use. hgkeychain:</p>

<ul>
<li><del><a href="http://toxic-public.googlecode.com/svn/trunk/Releases/hgkeychain.tar.bz2">Download: hgkeychain.tar.bz2</a></del></li>
<li><del><a href="http://toxic-public.googlecode.com/svn/trunk/Projects/hgkeychain/">Source Code</a></del></li>
<li><del><a href="http://toxic-public.googlecode.com/svn/trunk/Projects/hgkeychain/README">README</a></del></li>
</ul>

<p>And yes the source code is currently hosted in a Subversion repository :-) I did mention I&#8217;m in the middle of transitioning to Mercurial didn&#8217;t I?</p>

<hr />

<h2>Update</h2>

<p>I&#8217;ve update the project for Mercurial 1.1 &#8211; it should now work on 1.1 and also 1.0 (and lower). I&#8217;ve also decided to move the code to bitbucket instead: <a href="https://www.bitbucket.org/schwa/hgkeychain/">https://www.bitbucket.org/schwa/hgkeychain/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/hgkeychain/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Run Python Script: Amazon S3 Uploader</title>
		<link>http://toxicsoftware.com/s3_uploader/</link>
		<comments>http://toxicsoftware.com/s3_uploader/#comments</comments>
		<pubDate>Sat, 15 Dec 2007 04:32:42 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Amazon]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Run Python Script]]></category>
		<category><![CDATA[S3]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/s3_uploader/</guid>
		<description><![CDATA[To help illustrate the usefulness of the &#8220;Run Python Script&#8221; Automator Action I blogged about in my previous post, here&#8217;s an action that will upload files to the Amazon S3 Web Service. The script is pure Python and uses the extremely cool boto Python module to interact with Amazon web services. The script is really [...]]]></description>
			<content:encoded><![CDATA[<p>To help illustrate the usefulness of the &#8220;Run Python Script&#8221; Automator Action I blogged about in my <a href="http://toxicsoftware.com/run-python-script/">previous post</a>, here&#8217;s an action that will upload files to the Amazon S3 Web Service. The script is pure Python and uses the extremely cool <a href="http://code.google.com/p/boto/">boto</a> Python module to interact with Amazon web services. The script is really a sample of what could be done with The Run Python Script action, but I think it really shows off how the action helps to turn Automator into a great tool for interacting with Web Services.</p>

<p><a href="http://www.flickr.com/photos/61285556@N00/2111429437" title="View 'Amazon S3 Uploader Automator Action' on Flickr.com"><img src="http://farm3.static.flickr.com/2227/2111429437_83ca56bcd9_m.jpg" alt="Amazon S3 Uploader Automator Action" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/s3_uploader/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Run Python Script</title>
		<link>http://toxicsoftware.com/run-python-script/</link>
		<comments>http://toxicsoftware.com/run-python-script/#comments</comments>
		<pubDate>Fri, 14 Dec 2007 16:14:16 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[public]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Source]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/run-python-script/</guid>
		<description><![CDATA[Important see updates at end of post

I&#8217;ve written an Automator action that allows you to write python scripts directly inside your Automator workflow.



&#8220;Run Python Script&#8221; Automator action (catchy title) is written using Python and PyObjC (now built-in to Mac OS X 10.5). Apple already provides &#8220;Run AppleScript&#8221; and &#8220;Run Shell Script&#8221; actions with Automator which [...]]]></description>
			<content:encoded><![CDATA[<p><em>Important</em> see updates at end of post</p>

<p>I&#8217;ve written an Automator action that allows you to write python scripts directly inside your Automator workflow.</p>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110974754" title="View 'RunPythonScriptIcon' on Flickr.com"><img src="http://farm3.static.flickr.com/2237/2110974754_6e5540298b_o.png" alt="RunPythonScriptIcon" /></a></p>

<p>&#8220;<a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/Output/Run%20Python%20Script.action.tar.bz2">Run Python Script</a>&#8221; Automator action (catchy title) is written using Python and <a href="http://pyobjc.sourceforge.net/">PyObjC</a> (now built-in to Mac OS X 10.5). Apple already provides &#8220;Run AppleScript&#8221; and &#8220;Run Shell Script&#8221; actions with Automator which give Automator a high degree of flexibility. However Python is my preferred scripting language and by writing a custom action purely for Python I was able to take advantage of some PyObjC features that in my opinion make my action superior to the provided Apple scripting action. I&#8217;m releasing all the <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/">source code</a> to the action under the <a href="http://www.opensource.org/licenses/bsd-license.php">BSD Open Source</a> license.</p>

<p>One of the main advantages of the action is that Python (with the help of PyObjC) understands the AppleEvent descriptors that Automator uses to pass data between workflow actions. This allows the user to create a custom action that accepts and provides data of any type. In contrast Apple&#8217;s &#8220;Run Shell Script&#8221; action can only accept and provide text (usually limited to file paths). Some work does need to be done to make working with any data (which is represented by NSAppleEventDescriptor objects) more convenient.</p>

<p>The default Python script for a new action in a workflow follows:</p>

<pre><code>import sys

def main(input, *args, **kwargs):
    '''Your script goes here.'''
    print 'Hello world'
    return sys.stdout
</code></pre>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110978140" title="View 'RunPythonScriptMain' on Flickr.com"><img src="http://farm3.static.flickr.com/2286/2110978140_4c336656f7_m.jpg" alt="RunPythonScriptMain" /></a></p>

<p>This is pretty simple. The action will optionally convert the input into Python types (currently limited to converting typeAlias AppleEvent descriptors into path strings) to allow simple processing. Output is (optionally) converted from Python types to native Automator types. See the Examples directory for more.</p>

<p>The following screenshot shows the action used in a real workflow. This workflow asks the user for a keyword and then the Python action downloads photos from the <a href="http://morguefile.com/">morguefile</a> public stock photo archive that are related to the keyword. Once download it performs some processing on the files (scales them to 640 by 480) and produces a PDF &#8220;Contact Book&#8221; from the images.</p>

<p><a href="http://www.flickr.com/photos/61285556@N00/2110196661" title="View 'RunPythonScriptScreenshot' on Flickr.com"><img src="http://farm3.static.flickr.com/2169/2110196661_e9f178f475_m.jpg" alt="RunPythonScriptScreenshot" /></a></p>

<p>The <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/">source code</a> uses a 10.5 specific technique to create Python based bundles. It also has a simple Python syntax colouring NSTextView (using Python itself to colourise the source).</p>

<p>I&#8217;m calling the Action a 0.1 release and have some plans/ideas for further releases. See the <a href="http://bitbucket.org/schwa/toxic-public/src/tip/Projects/Automator/RunPythonScriptAction/TODO.txt">TODO list</a>.</p>

<p><em>Update</em>: I&#8217;ve added a <a href="http://toxicsoftware.com/s3_uploader/">sample script</a> showing how to upload files to Amazon S3 from within a workflow.</p>

<p>The code in subversion is a lot newer than the binary I&#8217;m linking to. If possible do a  checkout and build the plugin yourself.</p>

<p><em>Update</em>: This Automator action has issues on Snow Leopard and some Leopard versions. Use at your own risk.</p>

<p><em>Update</em>: Automator&#8217;s &#8220;Run Terminal Script&#8221; looks like it supports and understands Python native. That means, although my .action was better (syntax highlighting, better control of input and output, better logging, etc), I probably won&#8217;t bother to update it to Snow Leopard.</p>

<p><img src="http://toxicsoftware.com/wordpress/wp-content/uploads/Screen-shot-2009-10-16-at-11.02.36-AM.png" alt="Screen shot 2009-10-16 at 11.02.36 AM.png" border="0" width="25%" height="25%" /></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/run-python-script/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Mac OS Custom Icons and subversion don&#8217;t mix</title>
		<link>http://toxicsoftware.com/mac-os-custom-icons-and-subversion-dont-mix/</link>
		<comments>http://toxicsoftware.com/mac-os-custom-icons-and-subversion-dont-mix/#comments</comments>
		<pubDate>Thu, 21 Sep 2006 00:30:03 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[subversion]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/mac-os-custom-icons-and-subversion-dont-mix/</guid>
		<description><![CDATA[I had some big trouble with subversion today. I had upgraded to subversion 1.4 on both client and server a few days ago and today something went tits up with the repository on the server. I wont go into more detail here until I&#8217;ve reproduced and isolated the problem but suffice to say I deemed [...]]]></description>
			<content:encoded><![CDATA[<p>I had some big trouble with subversion today. I had upgraded to subversion 1.4 on both client and server a few days ago and today something went tits up with the repository on the server. I wont go into more detail here until I&#8217;ve reproduced and isolated the problem but suffice to say I deemed it worthwhile to try and restore my subversion repository from a recent dump file. Try was the operative word:</p>

<pre><code>[schwa@umbriel] Dumps$ admin create test
[schwa@umbriel] Dumps$admin load test &lt; dumpfile 'vnadmin: Invalid control character '0x0d' in path 'trunk/Path/To/Some/Directory/Icon&lt;
</code></pre>

<p>My attempt to recover from a dumpfile failed because my repository contained a folder with a custom icon. Crickey. I find it odd that subversion lets me check these bad files into subversion in the first place. But whatever, I had to recover this dump file. Fortunately there is a tool called &#8216;dumpfilter&#8217; that can be used to filter arbitrary paths in dump files. But after removing the first bad Icon file I found this particular repository had more than one. Instead of removing them by hand I started to write a shell script to automate the filtering process. Of course my shellfu is too low so I switched to Python:</p>

<pre><code>#!/usr/bin/python
import commands
import re
import sys
theInputFile = sys.argv[1]
theOutputFile = None
if len(sys.argv) &gt; 2:
    theOutputFile = sys.argv[2]
    thePattern = re.compile(r'^Node-path: (.+/Icon\r)$')
    thePaths = [thePattern.match(theLine).group(1) for theLine in open(theInputFile) if thePattern.match(theLine)]
    if theOutputFile == None:
        print 'Found the following paths:'
        for thePath in thePaths:
            print '\t\'%s\'' % thePath.replace('\r', '\\r')
        else:
            theCommand = 'dumpfilter exclude %s &lt; %s &gt; %s' % (' '.join(['\'%s\" % thePath for thePath in thePaths]), theInputFile, theOutputFile)
            print commands.getstatusoutput(theCommand)[1]
</code></pre>

<p>This script, when passed a path to an existing subversion dump file, will list all paths within the dump that contain custom icons. When passed a path to an existing dump file and the name of a new dump file it will remove all paths containing custom icons. You can then use this new dump file to populate your subversion repository without those pesky files. Update: From the comments, a link to Ryan Wilcox&#8217;s blog page concerning the problem (and a more detailed description of the solution): <a href="http://www.wilcoxd.com/blog/howto-get-out-the-icon-files-in-a-subversion-repo.html">http://www.wilcoxd.com/blog/howto-get-out-the-icon-files-in-a-subversion-repo.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/mac-os-custom-icons-and-subversion-dont-mix/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>WordPressTool</title>
		<link>http://toxicsoftware.com/wordpresstool/</link>
		<comments>http://toxicsoftware.com/wordpresstool/#comments</comments>
		<pubDate>Fri, 02 Jun 2006 04:33:20 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Sqlobject]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/wordpresstool/</guid>
		<description><![CDATA[Following on from my previous post I&#8217;ve uploaded some Python code that talks directly to a WordPress server via MySQL and Sqlobject.

WordPressTool downloads all postings into plain text files (one per posting). You can then treat your postings as regular text files: grep through them, perform global search and replaces, and so on. You can [...]]]></description>
			<content:encoded><![CDATA[<p>Following on from my <a href="/blog/expressionengine-to-wordpress/">previous post</a> I&#8217;ve uploaded some <a href="http://python.org">Python</a> code that talks directly to a <a href="http://wordpress.org">WordPress</a> server via MySQL and <a href="http://www.sqlobject.org/">Sqlobject</a>.</p>

<p><a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Projects/Misc/WordPressTool">WordPressTool</a> downloads all postings into plain text files (one per posting). You can then treat your postings as regular text files: grep through them, perform global search and replaces, and so on. You can then run the script again (don&#8217;t forget to tweak it to change the import operation to an output) and it will upload all the updated posts to the server.</p>

<p>I&#8217;ve just used it to fix all the links to my <a href="http://toxic-public.googlecode.com//">subversion repository</a> and it works great (<a href="http://barebones.com/">BBEdit&#8217;s</a> multi-file search and replace worked a treat.)</p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/wordpresstool/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ExpressionEngine to WordPress</title>
		<link>http://toxicsoftware.com/expressionengine-to-wordpress/</link>
		<comments>http://toxicsoftware.com/expressionengine-to-wordpress/#comments</comments>
		<pubDate>Fri, 02 Jun 2006 02:33:23 +0000</pubDate>
		<dc:creator>schwa</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[ExpressionEngine]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Sqlobject]]></category>
		<category><![CDATA[Weblog]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://toxicsoftware.com/expressionengine-to-wordpress/</guid>
		<description><![CDATA[I recently migrated this blog from ExpressionEngine to WordPress. This was rather a daunting proposition due to the none existence of tools for doing this. The best I could really hope for was publishing all my content as a large RSS feed and then importing this feed. Doing this would have meant I would have [...]]]></description>
			<content:encoded><![CDATA[<p>I <a href="/blog-updates/">recently</a> migrated this blog from ExpressionEngine to WordPress. This was rather a daunting proposition due to the none existence of tools for doing this. The best I could really hope for was publishing all my content as a large RSS feed and then importing this feed. Doing this would have meant I would have lost all my comments, trackbacks and probably categories and a lot more other information.</p>

<p>Fortunately I had already written some code to export the content from ExpressionEngine. All I needed to do was write some more code to import the data into WordPress.</p>

<p>I am posting this code online and briefly describing it so that others in similar situations might be able to transfer their content.</p>

<p><a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Projects/Misc/EE2WP%20Importer/ExpressionEngineExport.py">&#8220;ExpressionEngineExport.py&#8221;</a> uses <a href="http://www.sqlobject.org/">Sqlobject</a> to talk directly to the EE database (in my case via a SSH tunnel because this code was running on my local machine, talking to a firewalled MySQL server). I model as much of EE as I needed with Sqlobject classes then I &#8220;simply&#8221; walk through the sql tables sucking out data, formatting it and fixing it where possible and then writing it to an XML file.</p>

<p><a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Projects/Misc/EE2WP%20Importer/WordPressImporter.py">&#8220;WordPressImporter.py&#8221;</a> takes the XML file and via Sqlobject imports it directly into WordPress&#8217;s database.</p>

<p>The code works pretty reliably for me (I had a test server set up and tested the code quite thoroughly before importing the data into my <a href="/">&#8220;production&#8221;</a> server), however I make absolutely no guarantees that it will work for you. I am posting the code &#8220;as-is&#8221; in the hopes that it will be useful but I do not plan on supporting this code in any way.</p>

<p>The <a href="http://toxic-public.googlecode.com/svn/tags/BlogTag_20070927_729/Projects/Misc/EE2WP%20Importer/">code</a> can be found within my subversion directory.</p>
]]></content:encoded>
			<wfw:commentRss>http://toxicsoftware.com/expressionengine-to-wordpress/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
	</channel>
</rss>
