<?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>Es Tea Double Eye &#187; Python</title>
	<atom:link href="http://stii.co.za/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://stii.co.za</link>
	<description>You&#039;re never too old for a happy childhood</description>
	<lastBuildDate>Fri, 19 Aug 2011 02:20:18 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
	<atom:link rel='hub' href='http://stii.co.za/?pushpress=hub'/>
		<item>
		<title>Pubsubhubbub on Google appspot</title>
		<link>http://stii.co.za/article/pubsubhubbub-on-google-appspot/</link>
		<comments>http://stii.co.za/article/pubsubhubbub-on-google-appspot/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 05:36:04 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Article]]></category>
		<category><![CDATA[Afrigator]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[pubsubhubbub]]></category>
		<category><![CDATA[pushpress]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Wordpress]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=1144</guid>
		<description><![CDATA[It is the weirdest thing. I was having issues subscribing to blogs that is using pubsubhubbub.appspot.com using a Python script. It returned a 500 Internal Server error without fail. So I rewrote the process in PHP and like magic, it is gone&#8230; I used PHP and CURL to subscribe to the appspot service. In Python [...]]]></description>
			<content:encoded><![CDATA[<p>It is the weirdest thing. I was having issues subscribing to blogs  that is using <a href="http://stii.co.za/article/pubsubhubbub-on-afrigator/">pubsubhubbub.appspot.com</a> using a Python script. It returned a <a href="http://stii.co.za/article/pubsubhubbub-on-afrigator/">500 Internal Server</a> error without fail. So I rewrote the process in PHP and like magic, it is gone&#8230; I used <strong>PHP and CURL</strong> to subscribe to the appspot service. In <a href="http://stii.co.za/tag/python">Python</a> I used the <strong>urllib2 library</strong>. Somewhere in the back of my mind I vaguely remember appspot not liking urllib2, but I haven&#8217;t really checked due to time constraints. I&#8217;ll have a look soon, but if you&#8217;re going to use Python to subscribe to feeds, I would suggest trying to do so with <strong>CURL</strong>.</p>
<p>The good news is that all is good on <a href="http://afrigator.com">Afrigator</a> now. All blogs that are using some form of Pubsubhubbub service will be realtime in no time. </p>
<p>If you&#8217;re running on <strong>WordPress</strong> (not WordPress.com) and you have not yet installed <a href="http://wordpress.org/extend/plugins/pushpress/">PuSHPress</a>, please do so soon! </p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/article/pubsubhubbub-on-google-appspot/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The Google Go programming language</title>
		<link>http://stii.co.za/software-development/the-google-go-programming-language/</link>
		<comments>http://stii.co.za/software-development/the-google-go-programming-language/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 12:57:22 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Software Dev]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google go]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[pascal]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[programming languages]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=1059</guid>
		<description><![CDATA[Lately Google announced a wide array of new products and features. The Google Chrome browser, Google Wave, Android and Google Chrome OS are the ones immediately coming to mind. This morning I saw they released Go. Their own experimental programming language. Go is not a scripting (a.k.a. interpreted) language, but a compiled language like C [...]]]></description>
			<content:encoded><![CDATA[<p>Lately Google announced a wide array of new products and features. The Google Chrome browser, Google Wave, Android and Google Chrome OS are the ones immediately coming to mind. This morning I saw they released <a href="http://golang.org/">Go</a>. Their own experimental programming language. </p>
<p>Go is not a scripting (a.k.a. interpreted) language, but a compiled language like <strong>C or C++</strong>. It looks very, very simple compared to C/C++ and according to them it was born from their frustrations with said languages. This has potential to become popular should they drive it sufficiently. </p>
<p>The syntax of Go looks like a mix of Python, C, Java and Pascal. Have a look at this:</p>
<pre>
package main

import (
    "os";
    "flag";  // command line option parser
)

var omitNewline = flag.Bool("n", false, "don't print final newline")

const (
    Space = " ";
    Newline = "\n";
)

func main() {
    flag.Parse();   // Scans the arg list and sets up flags
    var s string = "";
    for i := 0; i < flag.NArg(); i++ {
        if i > 0 {
            s += Space
        }
        s += flag.Arg(i)
    }
    if !*omitNewline {
        s += Newline
    }
    os.Stdout.WriteString(s);
}
</pre>
<p>I can say this: It looks friendly! I like the sugar.</p>
<p>Some of the features makes a lot of sense and I hope this will evolve successfully. Just look at the names behind this little experimental project and you&#8217;re bound to get excited! <strong>I&#8217;d love to know what C and C++ stalwarts think</strong>.</p>
<p>PS: Love the origin of the name:</p>
<blockquote><p>“Ogle” would be a good name for a Go debugger.</p></blockquote>
<p>I concur.</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/software-development/the-google-go-programming-language/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Django tests fail on a new project</title>
		<link>http://stii.co.za/python/django-tests-fail-on-a-new-project/</link>
		<comments>http://stii.co.za/python/django-tests-fail-on-a-new-project/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 22:16:03 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[unittest]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=1013</guid>
		<description><![CDATA[This might be slightly confusing at first, but actually makes perfect sense if you think about it. If you have a brand new Django project and you run the tests it fails with a number of errors. # python manage.py test Creating test database... Creating table auth_permission Creating table auth_group Creating table auth_user Creating table [...]]]></description>
			<content:encoded><![CDATA[<p>This might be slightly confusing at first, but actually makes perfect sense if you think about it. If you have a brand new <a href="http://stii.co.za/tag/django">Django</a> project and you run the tests it fails with a number of errors.</p>
<pre>
# python manage.py test
Creating test database...
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Installing index for auth.Permission model
Installing index for auth.Message model
EE..E...EEEEEEE..................
======================================================================
ERROR: test_password_change_fails_with_invalid_old_password (django.contrib.auth.tests.views.ChangePasswordTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Library/Python/2.6/site-packages/django/contrib/auth/tests/views.py", line 156, in test_password_change_fails_with_invalid_old_password
    'new_password2': 'password1',
  File "/Library/Python/2.6/site-packages/django/test/client.py", line 313, in post
    response = self.request(**r)
  File "/Library/Python/2.6/site-packages/django/core/handlers/base.py", line 92, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/Library/Python/2.6/site-packages/django/contrib/auth/decorators.py", line 78, in __call__
    return self.view_func(request, *args, **kwargs)
  File "/Library/Python/2.6/site-packages/django/contrib/auth/views.py", line 160, in password_change
    }, context_instance=RequestContext(request))
  File "/Library/Python/2.6/site-packages/django/shortcuts/__init__.py", line 20, in render_to_response
    return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
  File "/Library/Python/2.6/site-packages/django/template/loader.py", line 103, in render_to_string
    t = get_template(template_name)
  File "/Library/Python/2.6/site-packages/django/template/loader.py", line 81, in get_template
    source, origin = find_template_source(template_name)
  File "/Library/Python/2.6/site-packages/django/template/loader.py", line 74, in find_template_source
    raise TemplateDoesNotExist, name
TemplateDoesNotExist: registration/password_change_form.html
...
</pre>
<p>In total 10 tests failed. At first I thought this was wrong. There must be something wrong with my Django installation. I consulted the <a href="http://docs.djangoproject.com/en/1.0/topics/testing/">Django documentation on testing Django apps</a> and all I could pick up was that when you run <strong>python manage.py test</strong> it runs the tests of all your <strong>INSTALLED_APPS</strong> in the <em>settings.py</em> file.</p>
<p>After a bit of searching, I saw a ticket was created for this and was closed with a <em>wontfix</em> resolution. It made sense since it is test cases that was not implemented yet. Doh! <strong>Test Driven Development</strong>.</p>
<p>I do think it could be useful if they added this to the Django docs as a note for n00bs like me.</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/django-tests-fail-on-a-new-project/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Call me anal, but I really like Django templates</title>
		<link>http://stii.co.za/python/call-me-anal-but-i-really-like-django-templates/</link>
		<comments>http://stii.co.za/python/call-me-anal-but-i-really-like-django-templates/#comments</comments>
		<pubDate>Fri, 02 Oct 2009 09:58:31 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=962</guid>
		<description><![CDATA[For all the wrong reasons, but still! I just love the fact that it actually uses a .html extension. Am I weird? I do feel a bit weird that I like something so arb. So the template files use the extension of what it actually contains? Wow, I love that. Revolutionary. Don&#8217;t ask me why [...]]]></description>
			<content:encoded><![CDATA[<p>For all the wrong reasons, but still! I just <em>love</em> the fact that it actually uses a <strong>.html extension</strong>. Am I weird? I do feel a bit weird that I like something so arb. So the template files use the extension of what it actually contains? Wow, I love that. Revolutionary. Don&#8217;t ask me why I just thought of that&#8230; I cannot answer that truthfully :P Feels like I&#8217;m being anal, since it doesn&#8217;t seem to matter to anyone else. Most other web development frameworks uses other file extensions. For example in PHP frameworks, the template files have a .php extension. Must be this glorious <strong>Rocktober</strong> day in Cape Town that is doing this to me!</p>
<p><a href="http://djangoproject.com"><img src="http://stii.co.za/wp-content/uploads/2009/04/django-logo-positive-400x139.png" alt="django-logo-positive" title="django-logo-positive" width="400" height="139" class="alignnone size-medium wp-image-574" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/call-me-anal-but-i-really-like-django-templates/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>The importance of documentation</title>
		<link>http://stii.co.za/software-development/the-importance-of-documentation/</link>
		<comments>http://stii.co.za/software-development/the-importance-of-documentation/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 22:46:02 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Software Dev]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=902</guid>
		<description><![CDATA[Very good post on open source documentation via @TheKeyboard » Open Source Is Really About Documentation – Twisted vs. Tornado. Chris Brain&#8217;s point in short is: I think I can give you an executive summary of this blog post: if the documentation for an open source project sucks, nobody but the most hardcore developers will [...]]]></description>
			<content:encoded><![CDATA[<p>Very good post on open source documentation via <a href="http://www.littlehart.net/atthekeyboard/2009/09/14/open-source-is-really-about-documentation/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss">@TheKeyboard » Open Source Is Really About Documentation – Twisted vs. Tornado</a>. Chris Brain&#8217;s point in short is:</p>
<blockquote><p><em>I think I can give you an executive summary of this blog post: if the documentation for an open source project sucks, nobody but the most hardcore developers will use it.</em>
</p></blockquote>
<p><a href="http://www.littlehart.net/atthekeyboard/2009/09/14/open-source-is-really-about-documentation/?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=rss"><img src='http://stii.co.za/wp-content/uploads/2009/09/DRAW-ANYTHING-363.gif' alt='' /></a></p>
<p>That couldn&#8217;t be more true! The documentation is just about as important as the application. The problem is that it takes time to maintain. Often we as developers are simply too lazy and &#8220;will update the documentation later&#8221;. I know I am like that, sadly&#8230; Will make it next years new years resolution to change that!</p>
<p>I do think that there could possibly be better ways to do documentation. Look at <a href="http://php.net">PHP</a></p>
<p style="text-align: center;">
<p>&#8216;s documentation. It is fairly simple and concise, but I have often found great value in the user comments and examples which you would find underneath every page. I don&#8217;t think it is perfect, but it sure helps.</p>
<p>User contributions play a big role in Open Source documentation and developers with blogs often write their examples on their blogs. I end up finding them by searching Google for it, but it would sure help much more if those posts were linked to the documentation. Something to consider, I think.</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/software-development/the-importance-of-documentation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Zen of Python</title>
		<link>http://stii.co.za/software-development/the-zen-of-python/</link>
		<comments>http://stii.co.za/software-development/the-zen-of-python/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 12:06:23 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Software Dev]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=857</guid>
		<description><![CDATA[Found at this Stack overflow gem. &#8220;Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.&#8221; :)]]></description>
			<content:encoded><![CDATA[<p>Found at this <a href="http://stackoverflow.com/questions/234075?sort=votes&#038;page=4#sort-top">Stack overflow gem</a>.</p>
<blockquote><p>&#8220;Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.&#8221;</p></blockquote>
<p>:)</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/software-development/the-zen-of-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTTP conditional GET with Python urllib2</title>
		<link>http://stii.co.za/python/http-conditional-get-with-python-urllib2/</link>
		<comments>http://stii.co.za/python/http-conditional-get-with-python-urllib2/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 08:47:46 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Afrigator]]></category>
		<category><![CDATA[conditional get]]></category>
		<category><![CDATA[ETag]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[Last-Modified-Date]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[urllib2]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=767</guid>
		<description><![CDATA[When aggregating or reading crap loads of RSS feeds, it makes little or no sense to read every feed every time you check, when most feeds is updated only once a day. To give you and idea, at Afrigator the size of the feeds are half a gig (500 MB), so if you do that [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://stii.co.za/wp-content/uploads/2009/07/python-logo-small.gif" alt="python-logo-small" title="python-logo-small" width="200" height="59" class="alignright size-full wp-image-769" />When aggregating or reading crap loads of RSS feeds, it makes little or no sense to read every feed every time you check, when most feeds is updated only once a day. To give you and idea, at <a href="http://afrigator.com">Afrigator</a> the size of the feeds are half a gig (500 MB), so if you do that every hour you consume 12 giga bytes of data in 24 hours. This simply to get about 2000 new blog posts per day.</p>
<p>To alleviate load off the system and data transfers, you can do a <strong>HTTP conditional GET</strong> which basically check the RSS feed&#8217;s HTTP headers to see whether or not the feed was updated since the last time you checked and if it was, you&#8217;ll process the feed, else just ignore it. It does this by checking the <strong>ETag</strong> and <strong>Last-Modified-Date</strong> HTTP header attributes. It also only fetches the headers and not the entire feed, so only a fraction of the data is retrieved. </p>
<pre>
...
req = urllib2.Request(url)

req.add_header("If-None-Match", etag)
req.add_header("If-Modified-Since", lastmodified)

opener = urllib2.build_opener(NotModifiedHandler())
url_handle = opener.open(req)

if hasattr(url_handle, 'code') and url_handle.code == 304:
    return
else:
    headers = url_handle.info()
    new_etag = headers.getheader("ETag")
    new_last_modified = headers.getheader("Last-Modified")

    if new_etag != None and new_last_modified != None:
        store_new_etag(new_etag, new_last_modified, self.id)

    #get the content and write to file
    content = url_handle.read()
...
</pre>
<p>If you&#8217;re interested to know the more technical aspects of what happens, see this <a href="http://www.artima.com/forums/flat.jsp?forum=122&#038;thread=15024">brilliant post</a>. If you plan to build a feed reader at all, you need to use this function. You will not only kill your bandwidth, but everybody else&#8217;s if you don&#8217;t use it. If you built your own blogging platform, you need to make sure that you add the necessary <strong>ETag</strong> and <strong>Last-Modified-Date</strong> headers to your RSS feed. Will tell you next time how to do that. If you are on WordPress, Blogger or Movable Type it should be fine.</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/http-conditional-get-with-python-urllib2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Django with apache and mod_wsgi issues</title>
		<link>http://stii.co.za/python/django-with-apache-and-mod_wsgi-issues/</link>
		<comments>http://stii.co.za/python/django-with-apache-and-mod_wsgi-issues/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 18:47:58 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Mobile Web]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[mod_wsgi]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=570</guid>
		<description><![CDATA[I ran into a fairly common error while setting up Django with mod_wsgi and Apache on Debian. What irritates me about it is that I didn&#8217;t pick it up right away, but I&#8217;ll blame the long Easter weekend for that. :P ImportError: Could not import settings 'mysite.settings' (Is it on sys.path? Does it have syntax [...]]]></description>
			<content:encoded><![CDATA[<p>I ran into a fairly common error while setting up <a href="http://stii.co.za/tag/django">Django</a> with <strong>mod_wsgi</strong> and <strong>Apache</strong> on <strong>Debian</strong>. What irritates me about it is that I didn&#8217;t pick it up right away, but I&#8217;ll blame the long Easter weekend for that. :P </p>
<p><img src="http://stii.co.za/wp-content/uploads/2009/04/django-logo-positive-400x139.png" alt="django-logo-positive" title="django-logo-positive" width="400" height="139" class="aligncenter size-medium wp-image-574" /></p>
<pre>
ImportError: Could not import settings 'mysite.settings'
(Is it on sys.path? Does it have syntax errors?):
No module named mysite.settings
</pre>
<p>My wsgi file looked like this:</p>
<pre>
import os, sys
sys.path.append('/home/djangoprojects/mysite/')
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi

_application = django.core.handlers.wsgi.WSGIHandler()

def application(environ, start_response):
    if environ['wsgi.url_scheme'] == 'https':
        environ['HTTPS'] = 'on'
    return _application(environ, start_response)
</pre>
<p>Like an idiot, I was looking everywhere for the issue, accept the glaring obvious reason. I checked permissions, created a .pth file for the project in the <strong>/site-packages/</strong> directory in the Python library. Trust me, I did everything, but the obvious thing.</p>
<p>See, here is that obvious reason:</p>
<p>I append the directory &#8220;<strong>/home/djangoprojects/mysite</strong>&#8221; to my <strong>sys.path</strong> which is wrong. Python then looks for the module &#8220;<strong>mysite</strong>&#8221; in the directory <strong>/home/djangoprojects/mysite</strong> which in fact doesn&#8217;t exist. Obvious, no? </p>
<p>To fix this problem, you need to append the directory &#8220;<strong>/home/djangoprojects/</strong>&#8221; to your <strong>sys.path</strong> and it will find the module <strong>mysite.settings</strong> no problem and it will run smooth.</p>
<p>Long weekend, surf on the brain. That&#8217;s what is wrong!</p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/django-with-apache-and-mod_wsgi-issues/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Switched to Python Fabric</title>
		<link>http://stii.co.za/python/switched-to-python-fabric/</link>
		<comments>http://stii.co.za/python/switched-to-python-fabric/#comments</comments>
		<pubDate>Wed, 04 Mar 2009 09:18:24 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Afrigator]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[fabric]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=497</guid>
		<description><![CDATA[We&#8217;ve been using Capistrano to deploy Afrigator to our various servers for a while now. I can seriously not complain or say anything bad about Capistrano. Thing is, I&#8217;m more familiar with Python than I am with Ruby, thus for me it just makes more sense for me to use Fabric. Here is a small [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve been using <a href="http://www.capify.org/" rel="nofollow">Capistrano</a> to deploy <a href="http://stii.co.za/tag/afrigator">Afrigator</a> to our various servers for a while now. I can seriously not complain or say anything bad about Capistrano. Thing is, I&#8217;m more familiar with <a href="http://stii.co.za/tag/python">Python</a> than I am with <strong>Ruby</strong>, thus for me it just makes more sense for me to use <a href="http://www.nongnu.org/fab/index.html"  rel="nofollow">Fabric</a>.</p>
<p>Here is a small example of how to write a typical <strong>deploy script with Python Fabric</strong>:</p>
<p>First, define your various servers which you need to deploy to. Ideally, you&#8217;ll have a test, staging and live server. Thus you&#8217;ll set them up as follows.</p>
<pre>
def test():
    config.fab_user = 'test_user_name'
    config.fab_hosts = ['test.yourserver.com']

def staging():
    config.fab_user = 'staging_user_name'
    config.fab_hosts = ['staging.yourserver.com']

def live():
    config.fab_user = 'live_user_name'
    config.fab_hosts = ['www1.yourserver.com', \
'www2.yourserver.com', 'www3.yourserver.com']
</pre>
<p>This allows you to deploy your code to the various servers. Please note, you need to setup automatic login for your different servers. See here how to do <a href="http://wp.uberdose.com/2006/10/16/ssh-automatic-login/" rel="nofollow">automatic logins</a>.</p>
<p>Next, write the steps you would take to deploy your site manually:</p>
<pre>
def deploy():
    "Deploy code to servers"
    msg = "deploying"
    require('fab_hosts', provided_by = [test,staging,live])
    local('svn ci -m "$(msg)"')
    run('svn export repos /path/to/repository/export/')
    run('cp -R /path/to/repository/export/* /path/to/your/site/')
</pre>
<p>To deploy to the staging server you can run the following command:</p>
<pre>
$ fab staging let:msg="Reason for check in" deploy
</pre>
<p>To deploy to the 3 live servers, all you do is:</p>
<pre>
$ fab live let:msg="Reason for check in" deploy
</pre>
<p>The command works as follows: <strong>fab</strong> is the command. <strong>live/stating/test</strong> are the environments you would like to load. If you said staging, it will do the commands in <strong>deploy</strong> for the staging server. The last part is the command you want to run. In this instance, <strong>deploy</strong>. </p>
<p>The <strong>let:msg=&#8221;Reason for check in&#8221;</strong> is the coolest bit! It basically allow you to <strong>override Fabric variables</strong>. If you look closely, in my deploy script I&#8217;ve set a variable <strong>msg</strong> to just say &#8220;deploy&#8221;. Now that is a stupid <a href="http://stii.co.za/tag/svn">SVN</a> message for a commit. In order to commit with meaningful messages, I override the msg variable with my own message. Simple, yet very effective!</p>
<p>You may want to write a number of different functions in a single fabfile. If you have 100 commands and you&#8217;re not one hundred percent sure, just do a:</p>
<pre>
$ fab list
</pre>
<p>and all the commands available to you will be printed with their description. <strong>Fabric rocks! <em>Seriously</em>.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/switched-to-python-fabric/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>How to calculate the days between two dates using Python. Quickly.</title>
		<link>http://stii.co.za/python/how-to-calculate-the-days-between-two-dates-using-python-quickly/</link>
		<comments>http://stii.co.za/python/how-to-calculate-the-days-between-two-dates-using-python-quickly/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 10:56:38 +0000</pubDate>
		<dc:creator>Stii</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[softwaredevelopment]]></category>
		<category><![CDATA[tools]]></category>

		<guid isPermaLink="false">http://stii.co.za/?p=331</guid>
		<description><![CDATA[This is one of those pretty useless things, but you never know when you might just have the need for something like this&#8230; I have not taken the time to investigate a quicker way using Bash, but my love of Python made me use it without even thinking twice! :) I first fired up the [...]]]></description>
			<content:encoded><![CDATA[<p>This is one of those pretty useless things, but you never know when you might just have the need for something like this&#8230; I have not taken the time to investigate a quicker way using <a href="http://stii.co.za/tag/bash/">Bash</a>, but my love of <a href="http://stii.co.za/tag/python/">Python</a> made me use it without even thinking twice! :)</p>
<p>I first fired up the interactive <strong>Python</strong> interpreter by simply typing the command python. Next, I imported the <strong>datetime module</strong>. Did a simple <strong>timedelta</strong> between two <strong>datetime objects</strong> and Jack&#8217;s your uncle.</p>
<pre>
$ python
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license"
for more information.
>>> import datetime
>>> print (datetime.date(2009, 03, 31) \
... - datetime.date(2009, 02, 06)).days
53
>>>
</pre>
<p><strong>Python</strong> not only is an excellent programming language, it is also a brilliant general purpose toolbox! <strong>Bash/Awk/whatever</strong> experts, is there a quicker way maybe? Would love to know. </p>
]]></content:encoded>
			<wfw:commentRss>http://stii.co.za/python/how-to-calculate-the-days-between-two-dates-using-python-quickly/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

