<?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>mFabrik - web and mobile development &#187; django</title>
	<atom:link href="http://blog.mfabrik.com/category/django/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.mfabrik.com</link>
	<description>Freedom delivered.</description>
	<lastBuildDate>Thu, 02 Sep 2010 13:25:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Python Interest Group Finland (PIG FI) &#8211; join now</title>
		<link>http://blog.mfabrik.com/2010/08/13/python-interest-group-finland-pig-fi-join-now/</link>
		<comments>http://blog.mfabrik.com/2010/08/13/python-interest-group-finland-pig-fi-join-now/#comments</comments>
		<pubDate>Fri, 13 Aug 2010 09:00:24 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[plone]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[finland]]></category>
		<category><![CDATA[sig]]></category>
		<category><![CDATA[user group]]></category>

		<guid isPermaLink="false">http://blog.mfabrik.com/?p=625</guid>
		<description><![CDATA[I have started a mailing list / Google group for Python Finnish community. http://groups.google.com/group/pigfi As far as I know such thing didn&#8217;t exist before. We discussed about the establishment of Python Finnish user group with several Python activists in Sauna Sprint few days ago (the event arranged by EESTEC and Plonistans, mid term report, final [...]]]></description>
			<content:encoded><![CDATA[<p>I have started a mailing list / Google group for Python Finnish community.</p>
<p><a href="http://groups.google.com/group/pigfi">http://groups.google.com/group/pigfi</a></p>
<p>As far as I know such thing didn&#8217;t exist before. We discussed about the establishment of Python Finnish user group with several Python activists in Sauna Sprint few days ago (the event arranged by EESTEC and Plonistans, <a href="http://eestec.net/news-and-offers/plone-sauna-sprint-mid-term-report">mid term</a> report, <a href="http://eestec.net/news-and-offers/plone-sauna-sprint-final-report">final report</a>). There used to exist Plone-related mailing list, but that&#8217;s pretty much dead now. If there are other parallel efforts I am not aware of them, but I really like to merge with the existing work whether it exists. I know at least Nokia, Finnish universities and several small enterprises are very active Python users in Finland.</p>
<p>Our goal is to establish a vibrant, self-sustaining, Python community of Finland. We want to promote the sharing of Python knowledge across organizational borders, the adoption of Python in corporate and hobbyist cultures and have jolly good time with other Python enthusiasts. This probably means discussion (in Finnish), events and  lots of, lots of, sauna. After all, the community will take the shape what suits it for the best, it is not forced externally.</p>
<p>The short term goal is to gather enough participants to have a meaningful community. So, <strong><a href="http://groups.google.com/group/pigfi">Join now!</a></strong>. You can use web interface, email or RSS to follow the discussion. Spread the word to make sure that the message reaches everyone. Tweet it. IRC it. Email it to your friends. SMS it to your parents. Go to streets and cry aloud &#8220;Rakastan Pythonia.&#8221;</p>
<p>For most of us being Python programmer is a choice you have made  or would like to take. Let&#8217;s together create an environment where this choice is fun and will generate great personal wealth for all of us.
<p>
<a href="http://blog.mfabrik.com"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/mfabrik-24.png"></img></a> <a href="http://blog.mfabrik.com">Read our blog</a> <a href="http://twitter.com/mfabrik"> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" style="vertical-align:middle;border:0"/></a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml">Subscribe mFabrik blog in a reader</a> <img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/twitter-24.png"></img></a> <a href="http://twitter.com/mfabrik">Follow us on Twitter</a> <a href="http://www.linkedin.com/in/ohtis"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/linkedin-24.png"></img></a> <a href="http://www.linkedin.com/in/ohtis">Mikko Ohtamaa on LinkedIn</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2010/08/13/python-interest-group-finland-pig-fi-join-now/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Applying monkey patches in Django middleware layer</title>
		<link>http://blog.mfabrik.com/2010/08/12/applying-monkey-patches-in-django-middleware-layer/</link>
		<comments>http://blog.mfabrik.com/2010/08/12/applying-monkey-patches-in-django-middleware-layer/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 22:04:19 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[plone]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[cufon]]></category>
		<category><![CDATA[decompose]]></category>
		<category><![CDATA[django-cms]]></category>
		<category><![CDATA[fcgi]]></category>
		<category><![CDATA[middleware]]></category>
		<category><![CDATA[monkey patch]]></category>
		<category><![CDATA[normalization]]></category>
		<category><![CDATA[umlaut]]></category>
		<category><![CDATA[unicode]]></category>

		<guid isPermaLink="false">http://blog.mfabrik.com/?p=619</guid>
		<description><![CDATA[Monkey patching is a technique to modify module functions or class methods in Python and other dynamic languages run-time. It differs from the traditional source code patching that it does not need separate utility or compilation process to become effective. This means that you can deploy patches to codebase not under your control with your [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Monkey_patch">Monkey patching</a> is a technique to modify module functions or class methods in Python and other dynamic languages run-time. It differs from the traditional source <a href="http://en.wikipedia.org/wiki/Patch_(Unix)">code patching</a> that it does not need separate utility or compilation process to become effective. This means that you can deploy patches to codebase not under your control with your application without extra effort. Monkey patching has been made famous by <a href="http://plone.org">Plone/Zope</a> community where there is even <a href="http://pypi.python.org/pypi/collective.monkeypatcher">collective.monkeypatcher add-on for managed monkey patching</a>.</p>
<p>Because monkey patches do not need a compilation stage, the patch will work with the future versions of the application, assuming the patched function or method is not changed. So you can &#8220;safely&#8221; update the patched software and the patch will apply to the new version without need to go to command-line to perform some cumbersome commands. However, it is the best practice of open source community to report the bugs and submit the fixing patches, as source code patch, in the corresponding issue trackers.</p>
<p>In Django context, you can use monkey patching to</p>
<ul>
<li>Fix bugs or modify features of Django core without touching the source code</li>
<li>Fix bugs or modify features of Django plug-ins (TinyMCE, filebrowser, Django CMS) without touching the source code</li>
</ul>
<p>Patches are usually applied when Python does module imports. You have a special module called &#8220;monkeypatches.py&#8221; and when that is imported, it applies the patches when the module body level code runs. However, it is difficult to find stable import point in Django to run monkey patching. Django does some really evil magic to initialize INSTALLED_APPS, database models and stuff and doing any kind of work during import causes headache.</p>
<p>So I figured out that you can apply monkey patches using middleware. Middleware applies the monkey patch when the first HTTP request hits the process (note that if you run preforked web server like FCGI every process has its own run-time code in memory). This technique, of course, cannot be used to monkey-patch things that happen before middleware processing, but it is not often needed.</p>
<p>Below is an example how to monkey-patch Django CMS to normalize its unicode output. <a href="http://github.com/sorccu/cufon/issues/issue/133">There was an issue with unicode characters</a> and this is a stop-gap measure to fix it. (I think the proper fix would be fix related <a href="http://cufon.shoqolate.com/generate/">Cufon </a> font renderin Javascript library).</p>
<p>We add our monkey patcher to loaded middleware in settings.py.</p>
<pre>MIDDLEWARE_CLASSES = (
    ...
    'foobar.middleware.FixCufonUnicodeNormalization',
)</pre>
<p>The actual monkey patching happens by fiddling with the class code in process_request(). Note that in this particular case we only need to transform the output of the original function, we can simply hold a reference into it, call it and perform our transformation on the result. This way our monkey patch do not hinder the orignal function and is update safe (it does not matter if the code of PlaceholderNode.render method changes).</p>
<pre>import unicodedata

# Orignal function we monkey-patched away
_orignal_render = None

def _patched_render(self, context):
    """ Normalize all unicode output of Placeholder nodes in Django templates """

    content = _orignal_render(self, context)

    # http://docs.python.org/library/unicodedata.html
    return unicodedata.normalize("NFC", content)

class FixCufonUnicodeNormalization(object):
    """ Fix issue with Cufon, user-generated HTML and unicode decomposed characters.

http://github.com/sorccu/cufon/issues/issue/133

    """ 

    def process_request(self, request):
        """ Install monkey-patch on demand.

        If monkey-patch has not been run in for this process (assuming multiple preforked processes),
        then do it now.

        """
        from cms.templatetags.cms_tags import PlaceholderNode

        global _orignal_render, _patched_render

        if not _orignal_render:
            # replace one of the class's method with own fixed version
            _orignal_render = PlaceholderNode.render
            PlaceholderNode.render = _patched_render</pre>
<p>As far as I know, monkey patching is something PHP cannot do <img src='http://blog.mfabrik.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />
<p>
<a href="http://blog.mfabrik.com"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/mfabrik-24.png"></img></a> <a href="http://blog.mfabrik.com">Read our blog</a> <a href="http://twitter.com/mfabrik"> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml"><img valign="middle" src="http://www.feedburner.com/fb/images/pub/feed-icon16x16.png" alt="" style="vertical-align:middle;border:0"/></a> <a href="http://feeds.feedburner.com/mFabrikWebAndMobileDevelopment" rel="alternate" type="application/rss+xml">Subscribe mFabrik blog in a reader</a> <img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/twitter-24.png"></img></a> <a href="http://twitter.com/mfabrik">Follow us on Twitter</a> <a href="http://www.linkedin.com/in/ohtis"><img valign="middle"  src="http://blog.mfabrik.com/wp-content/uploads/linkedin-24.png"></img></a> <a href="http://www.linkedin.com/in/ohtis">Mikko Ohtamaa on LinkedIn</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2010/08/12/applying-monkey-patches-in-django-middleware-layer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Building a mobile site and applications with Django and Python</title>
		<link>http://blog.mfabrik.com/2009/09/30/building-a-mobile-site-and-applications-with-django-and-python/</link>
		<comments>http://blog.mfabrik.com/2009/09/30/building-a-mobile-site-and-applications-with-django-and-python/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 08:46:52 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[pys60]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[technology]]></category>
		<category><![CDATA[analytics]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[apex vertex]]></category>
		<category><![CDATA[augmented reality]]></category>
		<category><![CDATA[bicycling]]></category>
		<category><![CDATA[bilingual]]></category>
		<category><![CDATA[browser]]></category>
		<category><![CDATA[browsercontrol]]></category>
		<category><![CDATA[capabilities]]></category>
		<category><![CDATA[darwin]]></category>
		<category><![CDATA[django-cms]]></category>
		<category><![CDATA[extjs]]></category>
		<category><![CDATA[google maps]]></category>
		<category><![CDATA[gps]]></category>
		<category><![CDATA[handset]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[lbs]]></category>
		<category><![CDATA[localhost]]></category>
		<category><![CDATA[location based]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[media]]></category>
		<category><![CDATA[mobile profile]]></category>
		<category><![CDATA[mod_python]]></category>
		<category><![CDATA[multichannel]]></category>
		<category><![CDATA[multilingual]]></category>
		<category><![CDATA[nokia]]></category>
		<category><![CDATA[oulu]]></category>
		<category><![CDATA[phonegap]]></category>
		<category><![CDATA[premium]]></category>
		<category><![CDATA[print]]></category>
		<category><![CDATA[publishing]]></category>
		<category><![CDATA[rtsp]]></category>
		<category><![CDATA[series 40]]></category>
		<category><![CDATA[series 60]]></category>
		<category><![CDATA[sniffing]]></category>
		<category><![CDATA[streaming]]></category>
		<category><![CDATA[symbiansigned]]></category>
		<category><![CDATA[tourism]]></category>
		<category><![CDATA[traffic statistics]]></category>
		<category><![CDATA[twinapex]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[upnorth]]></category>
		<category><![CDATA[user agent]]></category>
		<category><![CDATA[webkit]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://blog.twinapex.fi/?p=248</guid>
		<description><![CDATA[Recently we created a mobile site for an interactive bicycle tour. oulugo.mobi (you need to use mobile browser to access the site or you&#8217;ll get a redirect) is a multimedia enriched bicycle tour through the historic parts of the city of Oulu. All content is provided by OnGo. The route, which you can bicycle through is [...]]]></description>
			<content:encoded><![CDATA[<p>Recently <a href="http://www.twinapex.com">we</a> created a mobile site for an interactive bicycle tour. <a href="http://oulugo.mobi">oulugo.mobi</a> (you need to use mobile browser to access the site or you&#8217;ll get a redirect) is a multimedia enriched bicycle tour through the historic parts of <a href="http://ouka.fi/english/index.asp">the city of Oulu</a>. All content is provided by <a href="http://www.ongo.fi/en/index.htm">OnGo</a>.</p>
<p>The route, which you can bicycle through is drawn on Google Maps. There are nine  action points where the user can listen to streaming audio clips, with still images, in his/her mobile phone. This is sort of  augmented reality experience: The user sees the real world (where he/she is now bicycling) combined with the historic events (audio playback narrative). For example, at Linnansaari (a location on the route) you&#8217;ll see the actual 17th century castle ruins and the narrator tells how the castle exploded when fire, caused by a lighting, reached gunpowder warehouse&#8230; boom. The explosion caused stones fly over 400 meters.</p>
<p>Alternatively, the clips are available as podcasts from <a href="http://www.oulutourism.fi/oulugo/en_default.aspx">Oulu Tourism pages</a>. You can download them into your iPod for offline listening and use in conjuction with a paper map. This demostrates interesting mix of multichannel publishing: paper, web, mobile and podcasts.</p>
<p>The tour is bilingual in Finnish and English.</p>
<p>There exists unreleased iPhone application, based on <a href="http://phonegap.com">PhoneGap</a>, which allows the user to track his/her location real-time on the web page. We didn&#8217;t see it worth of trouble to go through Apple iPhone application review process. When location based service support comes for the browser this feature is indended to be included as the standard HTML5 feature of the service.</p>
<p>There also exists Nokia Series 60 mobile application, based on<a href="http://wiki.opensource.nokia.com/projects/PyS60"> PyS60</a> and Series 60<a href="http://www.forum.nokia.com/info/sw.nokia.com/id/47d8a7fe-768c-44e5-bc26-fcba0a05e35e/S60_Platform_Browser_Control_API_Guide_v2_0_en.pdf.html"> BrowserControl API</a>, which allows the user to track his/her location in real-time. The application provides wrapper around Series 60 WebKit control and allows Javascript to access phone native functions (GPS) over localhost socket communication. Like with Apple, we didn&#8217;t see real-time tracking feature interesting enough to go through Symbian Signed process to get our application released. Also, BrowserControl had seriousquality problems and we didn&#8217;t consider it stable enough for the end users. <a href="https://code.launchpad.net/~august-joki/pys60community/browsercontrol">Some work is available in PyS60 Community Edition repository</a>.</p>
<p>The service is hosted <a href="http://www.twinapex.com/solutions/outsourcing-hosting-and-maintenance-of-internet-and-mobile-systems">on Python specific virtual server on Twinapex services server farm</a>.</p>
<h2>Features</h2>
<ul>
<li>Premium content tailored for audio listening</li>
<li>Dubbed in English and Finnish by a professional voice actor</li>
<li>Bilingual: English/Finnish</li>
<li>Adapts for smartphones (WebKit based browsers) and low end phones (XHTML mobile profile browsers)</li>
<li>Streaming video and audio (RTSP / progressive HTTP download forv iPhone). Different audio quality is provided on depending on the handset features.</li>
<li>Screen resolution detection based on <a href="http://en.wikipedia.org/wiki/User_Agent">user agent sniffing</a>. Three different version of images are used.</li>
<li>Custom Google Maps component for mobile is used. The component adapts for different mobile phones based on sniffing. Features include zoom, show action point, show the current location, search street address name. This component can be published on a request.</li>
<li>Management interface features include video upload, video transcoding different mobile versions and editing bilingual content</li>
<li><a href="http://www.twinapex.com/products/mobile-publishing/apex-vertex/handset-database">Apex Vertex handset database is used to detect the user&#8217;s mobile phone capabilities</a></li>
<li><a href="http://www.twinapex.com/products/mobile-publishing/apex-vertex/reporting">Apex Vertex logging and traffic analytics capabilities are used for the site statistics</a></li>
</ul>
<h2>Software stack</h2>
<ul>
<li><a href="http://www.ubuntu.com">Ubuntu 8.04 Hardy Heron virtual server</a></li>
<li><a href="http://www.apache.org">Apache 2.2 / mod_python</a></li>
<li><a href="http://python.org">Python 2.5</a></li>
<li><a href="http://djangoproject.com">Django 1.0</a></li>
<li><a href="http://django-cms.org/">Django-CMS 1.0</a></li>
<li><a href="http://code.google.com/p/mobilesniffer/">mobile.sniffer Python package to provide abstraction over different handset databases</a></li>
<li><a href="http://www.twinapex.com/products/mobile-publishing/apex-vertex">Apex Vertex streaming</a> solution (RTSP based on Darwin streaming server by Apple)</li>
<li><a href="http://tinymce.moxiecode.com/">TinyMCE WYSIWYG editor</a></li>
<li><a href="http://developer.apple.com/opensource/server/streaming/index.html">Darwin streaming server</a></li>
<li><a href="http://extjs.com/">ExtJS</a> is extensively used in Apex Vertext management interface</li>
</ul>
<h2>Development effort</h2>
<p>Development time: Around 100 hours. Three different developers where involved. Used development tools: <a href="http://www.eclipse.org">Eclipse</a>, <a href="http://pydev.sourceforge.net/">PyDev</a>, <a href="http://subclipse.tigris.org/">Subclipse</a>, <a href="http://subversion.tigris.org/">Subversion</a>. There were around five meetings between the content provider and the technology provider. Few beta testing rounds using iPhone application were performed by bicycling in -10 celcius degrees weather (north and so on&#8230;). No polar bears were harmed during the creation of this mobile service.</p>
<p>The service is linked in from Oulu Tourism pages and thousands of paper brochures printed for Oulu summer season 2009.</p>
<p><strong style="font-weight: bold;">About the author Mikko Ohtamaa</strong></p>
<ul>
<li><a href="http://www.linkedin.com/in/ohtis  ">LinkedIn</a></li>
<li><a href="http://twitter.com/moo9000">Twitter</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2009/09/30/building-a-mobile-site-and-applications-with-django-and-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python code management &amp; deployment &#8211; a glance at zc.buildout and few others</title>
		<link>http://blog.mfabrik.com/2008/09/02/python-code-management-deployment-a-glance-at-zcbuildout-and-few-others/</link>
		<comments>http://blog.mfabrik.com/2008/09/02/python-code-management-deployment-a-glance-at-zcbuildout-and-few-others/#comments</comments>
		<pubDate>Tue, 02 Sep 2008 08:24:47 +0000</pubDate>
		<dc:creator>Tuukka Mustonen</dc:creator>
				<category><![CDATA[development tools]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[zope]]></category>
		<category><![CDATA[buildout]]></category>
		<category><![CDATA[code management]]></category>
		<category><![CDATA[paver]]></category>
		<category><![CDATA[virtualenv]]></category>
		<category><![CDATA[zc.buildout]]></category>

		<guid isPermaLink="false">http://blog.redinnovation.com/?p=104</guid>
		<description><![CDATA[We&#8217;ve been using zc.buildout for Plone deployment and it&#8217;s working out great. A few days ago implemented a buildout recipe for Django project deployment, automatic web configuration, symlinking, media-folder structuring etc. and while I got it working, I came up with twisted feelings. Buildout is from the creators of Zope (I suppose) so you can [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve been using <a href="http://pypi.python.org/pypi/zc.buildout/1.1.1">zc.buildout</a> for <a href="http://www.plone.org">Plone</a> deployment and it&#8217;s working out great. A few days ago implemented a buildout recipe for <a href="http://www.djangoproject.org">Django</a> project deployment, automatic web configuration, symlinking, media-folder structuring etc. and while I got it working, I came up with twisted feelings.</p>
<p>Buildout is from the creators of <a href="http://www.zope.org/">Zope</a> (I suppose) so you can expect a powerful project code management tool. The question is, however, whether or not it suits your needs. In my case I found out it too heavy. I mean, to add even a simple task you have to create a new &#8220;recipe&#8221; (a package) that does the tricks. Of course some recipes are generic (found from <a href="http://pypi.python.org">PyPi</a>) and you can just run them with your own INI options, but in my case I had to do some custom implementation. Creating a new python package isn&#8217;t that hard for sure <img src='http://blog.mfabrik.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  but there&#8217;s of course some learning curve, so the <em>real</em> question is should you spend time to learn it or not?</p>
<p>I found out that zc.buildout has some nice features like:</p>
<ul>
<li> Automatic requirements processing through setuptools</li>
<li>Automatic (yet simple) removal of directories during recipe uninstall</li>
<li>Clear structure (install(), update() &amp; uninstall() methods)</li>
<li>INI-syntax, python does have a clear syntax but INI is always clearer for a newbie</li>
<li>Easy script creation (adjust python paths somewhat automatically)</li>
<li>Easily repeatable</li>
<li>Passing of arguments from one recipe to another</li>
<li>etc.</li>
</ul>
<p>The problems?</p>
<ul>
<li>It takes a while to learn zc.buildout</li>
<li>It takes &#8216;another while&#8217; to learn to write recipes</li>
<li>Too much hassle for little things</li>
<li>INI-syntax is very limited in features</li>
<li>Buildout easily updates all your packages (that means also the ones you didn&#8217;t want to!)</li>
<li>Lack of documentation (it has good docs to get you going.. but after a while it leaves you with open questions)</li>
<li>Unnecessary overhead (for each script you launch, you&#8217;ll need a launcher script created via buildout)</li>
</ul>
<p>There&#8217;s no denying zc.buildout is powerful, but I wouldn&#8217;t use it for projects which need reasonable amount of customization. It&#8217;s just plain easier and quicker to write shell scripts and while those won&#8217;t provide you with any sort of ready tools you won&#8217;t propably need them. For bringing up somewhat static environment, where you don&#8217;t need to hack things (like that for Plone) it&#8217;s quite a decent option, however.</p>
<p>I also explored alternatives to zc.buildout. I&#8217;ve been reading about earlier virtualenv but haven&#8217;t really tried it out until now. It looks very promising and creates a more flexible environment compared to zc.buildout. Of course their goals are not exactly the same. Also, there are a few other alternatives out there, among them a new Python code management tool called <a href="http://www.blueskyonmars.com/projects/paver/">Paver</a> (just look at that cool logo.. it does remind you of Indiana Jones, does it not?). I glanced through the Paver docs and it looks like it <em>might</em> be the way to go (Paver also supports virtualenv), but didn&#8217;t quite get the grasp of the benefits just yet. Anyway, if you are still interested in code management and deployment, I&#8217;d recommend you to read the <a href="http://www.blueskyonmars.com/2008/04/22/paver-and-the-building-distribution-deployment-etc-of-python-projects/">Paver release announcement</a> and also <a href="http://www.blueskyonmars.com/projects/paver/foreword.html">Paver forewords</a>. They should clear things up.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2008/09/02/python-code-management-deployment-a-glance-at-zcbuildout-and-few-others/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Debugging Django memory leak with TrackRefs and Guppy</title>
		<link>http://blog.mfabrik.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/</link>
		<comments>http://blog.mfabrik.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/#comments</comments>
		<pubDate>Fri, 07 Mar 2008 04:24:03 +0000</pubDate>
		<dc:creator>Mikko Ohtamaa</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[garbage collector]]></category>
		<category><![CDATA[guppy]]></category>
		<category><![CDATA[heap]]></category>
		<category><![CDATA[leak]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[standalone]]></category>

		<guid isPermaLink="false">http://blog.redinnovation.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/</guid>
		<description><![CDATA[I run Django in a standalone long-running application (video encoding server). It leaked memory severely. By using htop, one was seeing two gigabytes reserved for /usr/bin/python after a while. Before starting the debugging session, I had no faintest idea what could be the cause of the problem. Django is robust technology &#8211; this kind of [...]]]></description>
			<content:encoded><![CDATA[<p>I run Django in a standalone long-running application (video encoding server). It leaked memory severely. By using <a href="http://htop.sourceforge.net/">htop</a>, one was seeing two gigabytes reserved for /usr/bin/python after a while. Before starting the debugging session, I had no faintest idea what could be the cause of the problem. Django is robust technology &#8211; this kind of things haven&#8217;t happened for me before. Since I was running Django in standalone mode, I suspected that some query cache does not get cleared. But random poking around the source code didn&#8217;t give any clues.</p>
<p>It was time to do some serious memory debugging for Python.</p>
<p>Python as is doesn&#8217;t leak memory, since it&#8217;s garbage collected virtual machine. All &#8220;leaks&#8221; are design problems in the application logic.I found <a href="http://www.python.org/%7Ejeremy/weblog/030410.html">a good primer here</a> what&#8217;s going inside Python&#8217;s memory management.</p>
<p>First I tried this nice <a href="http://cvs.zope.org/Zope3/test.py">TrackRefs class from Zope</a>. It relies on Python&#8217;s own in-interpreter functions to monitor objects.</p>
<pre>class TrackRefs:
    """Object to track reference counts across test runs."""

    def __init__(self, limit=40):
        self.type2count = {}
        self.type2all = {}
        self.limit = limit

    def update(self):
        obs = sys.getobjects(0)
        type2count = {}
        type2all = {}
        for o in obs:
            all = sys.getrefcount(o)

            if type(o) is str and o == '&lt;dummy key&gt;':
                # avoid dictionary madness
                continue
            t = type(o)
            if t in type2count:
                type2count[t] += 1
                type2all[t] += all
            else:
                type2count[t] = 1
                type2all[t] = all

        ct = [(type2count[t] - self.type2count.get(t, 0),
               type2all[t] - self.type2all.get(t, 0),
               t)
              for t in type2count.iterkeys()]
        ct.sort()
        ct.reverse()
        printed = False

        logger.debug("----------------------")
        logger.debug("Memory profiling")
        i = 0
        for delta1, delta2, t in ct:
            if delta1 or delta2:
                if not printed:
                    logger.debug("%-55s %8s %8s" % ('', 'insts', 'refs'))
                    printed = True

                logger.debug("%-55s %8d %8d" % (t, delta1, delta2))

                i += 1
                if i &gt;= self.limit:
                    break 

        self.type2count = type2count
        self.type2all = type2all</pre>
<p>You need to have <a href="http://mail.python.org/pipermail/python-list/1999-June/006123.html">Python compiled in debug mode to have sys.getobjects()</a> method. Luckily this beefed up Python binary is availalble from Ubuntu&#8217;s stock repository:</p>
<pre>sudo apt-get install python-dbg python-mysqldb-dbg</pre>
<p>Note that native Python extensions don&#8217;t work unless they are specifically compiled against the Python debug build (python-mysqldb-dbg)..</p>
<p>Then I add TrackRefs to my main loop:</p>
<pre>    def run(self):

        self.running = True

        logger.info("Started worker " + self.get_worker_id_string())

        # Memory leak tracking
        tracker = TrackRefs()

        while self.running:

            self.mark_for_download()

            self.process_downloads()

            self.process_encodings()

            tracker.update() # Dump memory here</pre>
<pre>            time.sleep(settings.WORKER_POLL_DELAY)</pre>
<p>And after running a while I start getting interesting results:</p>
<pre>7956 [2008-03-07 02:59:28,767] INFO Jobs needing sources to download 0
7956 [2008-03-07 02:59:28,768] DEBUG Processable jobs: 0
7956 [2008-03-07 02:59:29,754] DEBUG ----------------------
7956 [2008-03-07 02:59:29,754] DEBUG Memory profiling
7956 [2008-03-07 02:59:29,754] DEBUG                                                            insts     refs
7956 [2008-03-07 02:59:29,754] DEBUG &lt;type 'int'&gt;                                                 150   137406
7956 [2008-03-07 02:59:29,755] DEBUG &lt;type 'tuple'&gt;                                               117   130211
7956 [2008-03-07 02:59:29,755] DEBUG &lt;type 'dict'&gt;                                                  5     8331
7956 [2008-03-07 02:59:29,755] DEBUG &lt;type 'str'&gt;                                                   3    27643
7956 [2008-03-07 02:59:29,755] DEBUG &lt;type 'unicode'&gt;                                               3     4606
7956 [2008-03-07 02:59:29,755] DEBUG &lt;type 'list'&gt;                                                  3     3492
7956 [2008-03-07 02:59:29,756] DEBUG &lt;type 'frame'&gt;                                                 1      962
7956 [2008-03-07 02:59:29,756] DEBUG &lt;type 'cell'&gt;                                                  0    12948
7956 [2008-03-07 02:59:29,756] DEBUG &lt;type 'function'&gt;                                              0     9479</pre>
<p>Woah! Who reserved 130 000 ints and tuples? No wonder that soon python gulps 1 gigabytes of memory. Since this is the only number which grows during the main loop cycling and there is no references to classes or objects debugging becomes a bit more difficult. I need to try to cross-reference the difficult tuple objects.</p>
<p>This didn&#8217;t go well &#8211; with  gc.get_referrers()  recurive parsing I got some results (example below).  But it became soom clearthat  debug references from the system itself was impossible: the memory debugging code will always create nasty cyclic references to the system, since it needs to track the objects. I gave up. There <span style="font-weight: bold">had to be</span> something better.</p>
<pre>9154 [2008-03-07 04:05:23,571] DEBUG /var/lib/python-support/python2.5/MySQLdb/connections.pyc
9154 [2008-03-07 04:05:23,571] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,572] DEBUG defaulterrorhandler
9154 [2008-03-07 04:05:23,572] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,572] DEBUG string_literal
9154 [2008-03-07 04:05:23,572] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,573] DEBUG unicode_literal
9154 [2008-03-07 04:05:23,573] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,573] DEBUG string_decoder
9154 [2008-03-07 04:05:23,573] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,573] DEBUG __exit__
9154 [2008-03-07 04:05:23,574] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,574] DEBUG begin
9154 [2008-03-07 04:05:23,574] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,574] DEBUG __init__
9154 [2008-03-07 04:05:23,574] DEBUG &lt;type 'function'&gt;
9154 [2008-03-07 04:05:23,575] DEBUG show_warnings</pre>
<p>There was: <a href="http://guppy-pe.sourceforge.net/guppy.html">Guppy</a>. Thank you Sverker Nilsson! You saved my day.</p>
<p>Since the API of Guppy is a <span style="font-style: italic">little</span> eccentric, here are some examples for you:</p>
<pre># init heapy
heapy = guppy.hpy()

# Print memory statistics
def update():
  print heapy.heap()

# Print relative memory consumption since last sycle
def update():
   print heapy.heap()
   heapy.setref()

# Print relative memory consumption w/heap traversing
def update()
    print heapy.heap().get_rp(40)
    heapy.setref()</pre>
<p>With heapy.heap() ; heapy.setref() I got this output:</p>
<pre>Partition of a set of 12 objects. Total size = 3544 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0      3  25     2244  63      2244  63 unicode
     1      2  17      708  20      2952  83 types.FrameType
     2      3  25      432  12      3384  95 dict (no owner)
     3      3  25      120   3      3504  99 str
     4      1   8       40   1      3544 100 list</pre>
<p>One adds get_rp() travelsal magic and everything becomes clear:</p>
<pre>Reference Pattern by &lt;[dict of] class&gt;.
 0: _ --- [-] 14 (dict (no owner) | list | str | types.FrameType | types.Gene...
 1: a      [-] 3 dict (no owner): 0x8c11f34*2, 0x8c1bd54*2, 0x8c1f854*2
 2: aa ---- [-] 1 list: 0x833c504*18
 3: a3       [-] 1 dict of django.db.backends.mysql.base.DatabaseWrapper: 0x8...
 4: a4 ------ [-] 1 dict (no owner): 0x83a65d4*2
 5: a5         [R] 1 guppy.heapy.heapyc.RootStateType: 0xb787c7a8L
 6: a3b ----- [-] 1 django.db.backends.mysql.base.DatabaseWrapper: 0x8356a34
 7: a3ba       [S] 7 dict of module: ..db, ..models, ..query, ..transaction...
 8: b ---- [S] 1 types.FrameType: &lt;&lt;lambda&gt; at 0x8b16ecc&gt;
 9: c      [-] 2 list: 0x833c504*18, 0xb7dafe6cL*5
&lt;Type e.g. '_.more' for more.&gt;</pre>
<p>What there could in DatabaseWrapper object which is growing and growing&#8230; query debugger. Django keeps track of all queries for debugging purposes (connection.queries). This list is reseted at the end of HTTP request. But in standalone mode, there are no requests. So you need to manually reset to queries list after each working cycle.</p>
<pre>        while self.running:

            self.mark_for_download()

            self.process_downloads()

            self.process_encodings()

            tracker.update()

            time.sleep(settings.WORKER_POLL_DELAY)

            # Clear database connection ad reset query debugger
            # between cycles to make sure that
            # related resources get released
            reset_queries()
            connection.close()

            print str(connection.queries)</pre>
<p>But even after this fix, I got increase in tuple and int usage when monitoring with TrackRefs. But when I run heapy.heap() alone, there is no increase. So the tuple and int consumption must have been caused by TrackRef, sys.getobjects, gc, etc. magic itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.mfabrik.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
