<?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>Zen and the Art of Programming &#187; Python</title>
	<atom:link href="http://programmingzen.com/category/python/feed/" rel="self" type="application/rss+xml" />
	<link>http://programmingzen.com</link>
	<description>By Antonio Cangiano, Software Engineer &#38; Technical Evangelist at IBM</description>
	<lastBuildDate>Wed, 21 Jul 2010 22:12:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Thoughts on Clojure</title>
		<link>http://programmingzen.com/2010/07/09/thoughts-on-clojure/</link>
		<comments>http://programmingzen.com/2010/07/09/thoughts-on-clojure/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 18:00:32 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://programmingzen.com/?p=1225</guid>
		<description><![CDATA[Lisp has had a tremendous impact on the world of programming. Even though Common Lisp and Scheme &#8212; the two main Lisp dialects &#8212; may not be considered mainstream today, several popular languages have been influenced by one or both of them. It isn&#8217;t stretching things too much to say that both Ruby and Python [...]]]></description>
			<content:encoded><![CDATA[<p>Lisp has had a tremendous impact on the world of programming. Even though Common Lisp and Scheme &mdash; the two main Lisp dialects &mdash; may not be considered mainstream today, several popular languages have been influenced by one or both of them.</p>
<p>It isn&#8217;t stretching things too much to say that both Ruby and Python can be seen as slower, easier (for beginners), object-oriented, infix Lisp dialects.</p>
<blockquote><p>Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that. But it is nicer to ordinary people. &mdash; Yukihiro &#8220;Matz&#8221; Matsumoto</p></blockquote>
<p>Ruby and Python aren&#8217;t intimidating and remain very approachable for absolute beginners. Furthermore, their approachability is not confined to the language design itself, but transcends into the community and ecosystem that surrounds them.</p>
<p>I&#8217;m not here to discuss how languages like Ruby and Python managed to become more popular than major Lisp dialects nowadays. I&#8217;d rather focus on how these gentler introductions to functional programming are acting as gateway drugs to Lisp for many developers.</p>
<p>A community that values metaprogramming and is obsessed with the construction of DSLs (Domain Specific Languages) like the Ruby&#8217;s is, will no doubt find in Lisp a valuable ally. Plus, if you know Ruby inside and out, you should find Lisp to be easy enough to learn.</p>
<p>To attract Ruby developers though, Lisp has to offer something more than just a set of powerful features. You could say that Rails is enough of a reason to learn and use Ruby. But what is Lisp able to solve all that better than Ruby? I&#8217;ll answer that question by focusing on a specific dialect of Lisp, that I and continually more Ruby developers are getting into: <a href="http://clojure.org">Clojure</a>.</p>
<p>It wouldn&#8217;t be fair to characterize the Lisp community as stagnant, but Clojure is definitely a welcomed dose of new blood. Clojure is a JVM-based modern Lisp designed for concurrency, which elegantly includes a set of carefully chosen features that are not easily found in mainstream languages.</p>
<p>In my opinion, Clojure has three main advantages over Ruby:</p>
<ul>
<li>It&#8217;s much faster than Ruby, which makes it a better choice for intensive processing. (<a href="http://www.infoq.com/articles/flightcaster-clojure-rails">FlightCaster</a> for example, uses both Rails and Clojure. Rails for the &#8220;front-end&#8221; and Clojure for the heavy lifting/forecasting.)</li>
<li>It greatly simplifies concurrent programming, making the language more future-proof as hardware manufacturers continue to produce processors with more CPU cores.</li>
<li>Clojure emphasizes functional programming and tries to minimize side effects.</li>
</ul>
<p>Clojure&#8217;s interoperability with Java resolves the issue of only having a few available libraries, which often affects new languages. It also helps in getting people to use the language within the enterprise world where Java still dominates.</p>
<p>Of all the &#8220;new&#8221; languages out there, I find Clojure to be the most fun, interesting and pragmatic: it&#8217;s something worth getting excited about. I don&#8217;t really care if it turns out to be the next Ruby or not, it&#8217;s a language that&#8217;s worth knowing and using. (If you haven&#8217;t tried it yet, a decent, short introductory book is the recently published <a href="http://programmingzen.com/recommends/?1430272317">Practical Clojure</a>.)</p>
<p>Clojure&#8217;s popularity may even bring more attention to Lisp in general (for example, most <a href="http://programmingzen.com/recommends/?0262011530">must-read</a> literature uses Scheme or Common Lisp). Perhaps then, it may indirectly help introduce more traditional Lisp dialects to a new generation of programmers.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/07/09/thoughts-on-clojure/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>DB2 support for Django 1.2 is here</title>
		<link>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/</link>
		<comments>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 02:32:02 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1135</guid>
		<description><![CDATA[The latest release of the IBM Adapter for Django now supports Django 1.2. Aside from enabling you to use the most recent version of Django, this release adds a few new goodies into the mix, that I&#8217;m sure many will appreciate. For example, IBM&#8217;s adapter (through the underlying DBI wrapper) now uses persistent connections, which [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://code.google.com/p/ibm-db/">latest release</a> of the <span class="caps">IBM</span> Adapter for Django now supports <a href="http://code.djangoproject.com/wiki/Version1.2Roadmap">Django 1.2</a>. Aside from enabling you to use the most recent version of Django, this release adds a few new goodies into the mix, that I&#8217;m sure many will appreciate.</p>
<p>For example, IBM&#8217;s adapter (through the underlying <span class="caps">DBI</span> wrapper) now uses persistent connections, which are especially helpful when dealing with Django &#8211; as it lacks connection pooling. (Of course DB2 also has the Connection Concentrator to aid in reducing the usage of server resources and improving scalability.)</p>
<p>Furthermore, the adapter adds support for the <span class="caps">DECIMAL</span> datatype, a necessary feature when dealing with money and currencies. Various enhancements and bug fixes were included too; <a href="http://groups.google.com/group/ibm_db/browse_thread/thread/c842df0e8803e517">check</a> <a href="http://groups.google.com/group/ibm_db/browse_thread/thread/2cb45b1b966f8a8c">them</a> out on Google Groups.</p>
<p>As a reminder, <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C</a> is an absolutely free of charge version of DB2 and it&#8217;s production ready (not a toy version). You can <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">download it from here</a>. Take it for a spin, experiment &#8211; chances are you&#8217;ll like it. If you need a guide to getting started, be sure to check out this <a href="http://www.ibm.com/developerworks/wikis/display/db2/free+book-+getting+started+with+db2+express-c">free e-book</a> by my colleagues Raul, Ian, and Rav.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/03/30/db2-support-for-django-1-2-is-here/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Free Python screencast about solving mazes</title>
		<link>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/</link>
		<comments>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 12:00:26 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Screencasts]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1133</guid>
		<description><![CDATA[ThinkCode.TV&#8217;s English site is going to be launched on April 19th. To celebrate the upcoming launch and whet your appetite, a 19 minute long screencast about solving ASCII mazes with a few lines of Python code was just released for free. This video serves to illustrate Python&#8217;s elegance and power, as well as ThinkCode.TV&#8217;s approach [...]]]></description>
			<content:encoded><![CDATA[<p>ThinkCode.TV&#8217;s English site is going to be launched on April 19th. To celebrate the upcoming launch and whet your appetite, a 19 minute long screencast about solving ASCII mazes with a few lines of Python code was just released for free. This video serves to illustrate Python&#8217;s elegance and power, as well as ThinkCode.TV&#8217;s approach to screencasts and education.</p>
<p align="center"><a href="http://thinkcode.tv/free"><img src="http://antoniocangiano.com/wp-content/uploads/2010/03/pybite.png" alt="Free Python Screencast" title="A-mazing Python" style="border: none;" /></a></p>
<p>In order to download the screencast, you don&#8217;t need a credit card, to provide your address or even your last name. Just <a href="http://thinkcode.tv/free"><strong>head on over to this page</strong></a> and join the newsletter. Upon confirming your subscription, you will immediately receive an email with links to DRM-free, 720p HD files in the formats QuickTime Movie (.mov), AVI and Ogg Theora (.ogv). These videos are in English, prepared by a published serial author on the subject of Python/Django, and narrated by a native English speaker. They also include optional subtitles in the .srt format, as well as the source code which is released under the MIT license, as is customary for ThinkCode.TV to do.</p>
<p>I hope you enjoy the free screencast and stay tuned for the launch in three weeks. </p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2010/03/29/free-python-screencast-about-solving-mazes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Benchmarking Tornado vs. Twisted Web vs. Tornado on Twisted</title>
		<link>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/</link>
		<comments>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/#comments</comments>
		<pubDate>Sun, 13 Sep 2009 12:07:51 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1104</guid>
		<description><![CDATA[FriendFeed, which was recently acquired by Facebook, just released an interesting piece of open source software. Tornado is an open source version of the scalable, non-blocking web server and tools that power FriendFeed. The FriendFeed application is written using a web framework that looks a bit like web.py or Google&#8217;s webapp, but with additional tools [...]]]></description>
			<content:encoded><![CDATA[<p>FriendFeed, which was recently acquired by Facebook, just released an interesting piece of open source software.</p>
<blockquote><p><a href="http://www.tornadoweb.org/">Tornado</a> is an open source version of the scalable, non-blocking web server and tools that power FriendFeed. The FriendFeed application is written using a web framework that looks a bit like web.py or Google&#8217;s webapp, but with additional tools and optimizations to take advantage of the underlying non-blocking infrastructure.</p></blockquote>
<p><big><strong>The story so far</strong></big></p>
<p>This release generated widespread interest among the Python and open source development communities. Rightfully so. There are many reasons to like Tornado. To begin with, it&#8217;s fast &mdash; and that&#8217;s fundamental for a web server. By using nginx as a load balancer and a static file server, and running a few Tornado instances (usually one per core available on the machine) it&#8217;s possible to handle thousands upon thousands of concurrent connections on relatively modest hardware; and this isn&#8217;t just theory. Tornado has already proven its worth in the field, by allowing FriendFeed to scale graciously.</p>
<p>Tornado is not only a fast web server, it acts as a very lightweight application framework as well. As such, it&#8217;s an appealing alternative to well established frameworks to the growing group of developers who&#8217;d like to develop &#8220;closer to the metal&#8221; and avoid the baggage associated with full-fledged web frameworks. The two things combined make Tornado ideal for developing &#8220;real time&#8221; web services and applications.</p>
<p>The feedback so far hasn&#8217;t been all positive though. <a href="http://glyph.twistedmatrix.com/2009/09/what-i-wish-tornado-were.html">Criticism of the project</a> has mainly focused on the lack of test coverage and the fact that FriendFeed has opted not to contribute to, and improve on, the existing Twisted Web project (which has similar goals). To make things worse, there were a few nonchalant comments about it as well. Performance issues and lack of ease of use were the reported motivations for starting a new project from scratch.</p>
<p>Dustin Sallings started working on a hybrid solution (henceforth <a href="http://dustin.github.com/2009/09/12/tornado.html">Tornado on Twisted</a>) that would reportedly keep the good parts that Tornado introduced, while using Twisted as its core for networking and HTTP parsing.</p>
<p>At this point I became naturally curious about the speed of these three web servers. Is Tornado really faster than Twisted Web? And what about Tornado on Twisted, would it be faster or slower? Let&#8217;s find out.</p>
<p><big><strong>Benchmark results</strong></big></p>
<p>I ran a simple Hello World app for all three web servers. All the web servers were run in standalone mode without a load balancer. I stress tested the web servers with httperf using a progressively larger amount of concurrent requests. 100,000 requests were generated for each test. The web servers were run on a desktop machine with an Intel® Core™2 Quad Processor Q6600 (8M Cache, 2.40 GHz, 1066 MHz FSB) processor and 8GB of RAM. The operating system of choice was Ubuntu 9.04 (x86_64).</p>
<p>Without further ado, here are the results:</p>
<p align="center"><img src="http://antoniocangiano.com/images/python-throughput.png" alt="Throughput for Tornado, Twisted, and Tornado on Twisted" /></p>
<p>As you can see Tornado turned out to be faster than the rest of the Python web servers. Handling a peak of almost 3900 req/s with a single front-end and on commodity hardware is nothing to sneer at.</p>
<p>Twisted Web didn&#8217;t do too bad either (max. 2703.7 req/s), but the difference in performance is noticeable. Likewise, the performance of Tornado on Twisted was virtually identical to that of Twisted Web.</p>
<p>There you have it. I was curious about the possible outcome and now I know. Remember, this is a report on the numbers I got on my machine, not a research paper. But I hope that you find them interesting nevertheless.</p>
<p><big><strong>Show me the code</strong></big></p>
<p>Tornado:</p>
<div class="highlight">
<pre>
<span class="kn">import</span> <span class="nn">tornado.httpserver</span>
<span class="kn">import</span> <span class="nn">tornado.ioloop</span>
<span class="kn">import</span> <span class="nn">tornado.options</span>
<span class="kn">import</span> <span class="nn">tornado.web</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="kn">from</span> <span class="nn">tornado.options</span> <span class="kn">import</span> <span class="n">define</span><span class="p">,</span> <span class="n">options</span>

<span class="n">define</span><span class="p">(</span><span class="s">&quot;port&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mf">8888</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;run on the given port&quot;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MainHandler</span><span class="p">(</span><span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">RequestHandler</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;Hello, world!&quot;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">()</span>
    <span class="n">application</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">([</span>
        <span class="p">(</span><span class="s">r&quot;/&quot;</span><span class="p">,</span> <span class="n">MainHandler</span><span class="p">),</span>
    <span class="p">])</span>
    <span class="n">http_server</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">httpserver</span><span class="o">.</span><span class="n">HTTPServer</span><span class="p">(</span><span class="n">application</span><span class="p">)</span>
    <span class="n">http_server</span><span class="o">.</span><span class="n">listen</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">port</span><span class="p">)</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">ioloop</span><span class="o">.</span><span class="n">IOLoop</span><span class="o">.</span><span class="n">instance</span><span class="p">()</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre>
</div>
<p>Twisted Web:</p>
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">epollreactor</span>
<span class="n">epollreactor</span><span class="o">.</span><span class="n">install</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>
<span class="kn">from</span> <span class="nn">twisted.web</span> <span class="kn">import</span> <span class="n">server</span><span class="p">,</span> <span class="n">resource</span>

<span class="k">class</span> <span class="nc">Simple</span><span class="p">(</span><span class="n">resource</span><span class="o">.</span><span class="n">Resource</span><span class="p">):</span>
    <span class="n">isLeaf</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="k">def</span> <span class="nf">render_GET</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&quot;Hello, world!&quot;</span>

<span class="n">site</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">Site</span><span class="p">(</span><span class="n">Simple</span><span class="p">())</span>
<span class="n">reactor</span><span class="o">.</span><span class="n">listenTCP</span><span class="p">(</span><span class="mf">8888</span><span class="p">,</span> <span class="n">site</span><span class="p">)</span>
<span class="n">reactor</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</pre>
</div>
<p>Tornado on Twisted:</p>
<div class="highlight">
<pre><span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">epollreactor</span>
<span class="n">epollreactor</span><span class="o">.</span><span class="n">install</span><span class="p">()</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>

<span class="kn">import</span> <span class="nn">tornado.options</span>
<span class="kn">import</span> <span class="nn">tornado.twister</span>
<span class="kn">import</span> <span class="nn">tornado.web</span>
<span class="kn">import</span> <span class="nn">logging</span>

<span class="kn">from</span> <span class="nn">tornado.options</span> <span class="kn">import</span> <span class="n">define</span><span class="p">,</span> <span class="n">options</span>

<span class="n">define</span><span class="p">(</span><span class="s">&quot;port&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mf">8888</span><span class="p">,</span> <span class="n">help</span><span class="o">=</span><span class="s">&quot;run on the given port&quot;</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">MainHandler</span><span class="p">(</span><span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">RequestHandler</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">&quot;Hello, world!&quot;</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="n">tornado</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">parse_command_line</span><span class="p">()</span>
    <span class="n">application</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">([</span>
        <span class="p">(</span><span class="s">r&quot;/&quot;</span><span class="p">,</span> <span class="n">MainHandler</span><span class="p">),</span>
    <span class="p">])</span>

    <span class="n">site</span> <span class="o">=</span> <span class="n">tornado</span><span class="o">.</span><span class="n">twister</span><span class="o">.</span><span class="n">TornadoSite</span><span class="p">(</span><span class="n">application</span><span class="p">)</span>
    <span class="n">reactor</span><span class="o">.</span><span class="n">listenTCP</span><span class="p">(</span><span class="n">options</span><span class="o">.</span><span class="n">port</span><span class="p">,</span> <span class="n">site</span><span class="p">)</span>

    <span class="n">reactor</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">main</span><span class="p">()</span>
</pre>
</div>
<p><strong>UPDATE (September 14, 2009):</strong></p>
<ul>
<li>The original version of this post included Unicorn as well. This wasn&#8217;t fair however, since it&#8217;s not an asynchronous web server.</li>
<li>EventMachine HTTP Server was added, but I have since decided to remove it as I prefer to let the article be a fair comparison between asynchronous Python web servers.</li>
<li>I initially used Apache Benchmark (ab). The results were misleading at best. I re-ran the tests with httperf and updated the results above.</li>
<li>Stock Tornado couldn&#8217;t be tested with httperf because their HTTP Server doesn&#8217;t implement getClientIP(). I had to manually modify a method to return the remote ip address. This may introduce a very minimal advantage for Tornado, but it should be negligible in this context.</li>
<li>I modified the examples for Twisted and Tornado on Twisted, to ensure that both took advantage of the epoll-based reactor.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/13/benchmarking-tornado-vs-twisted-web-vs-tornado-on-twisted/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Improve the speed and security of your SQL queries</title>
		<link>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/</link>
		<comments>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 05:15:38 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1101</guid>
		<description><![CDATA[An easy way to improve the performance and security of SQL queries is to replace literals with parameters. By replacing literal values with parameters, advanced relational databases will be able to compile your queries and have their execution plans cached. This saves time and precious resources when the same query (minus the actual values) is executed [...]]]></description>
			<content:encoded><![CDATA[<p>An easy way to improve the performance and security of SQL queries is to replace literals with parameters. By replacing literal values with parameters, advanced relational databases will be able to compile your queries and have their execution plans cached. This saves time and precious resources when the same query (minus the actual values) is executed over and over.</p>
<p>Consider the following series of queries:</p>
<div class="highlight">
<pre><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">100</span> <span class="k">AND</span> <span class="mi">499</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">500</span> <span class="k">AND</span> <span class="mi">999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">1000</span> <span class="k">AND</span> <span class="mi">1999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">2000</span> <span class="k">AND</span> <span class="mi">4999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">5000</span> <span class="k">AND</span> <span class="mi">9999</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="mi">10000</span> <span class="k">AND</span> <span class="mi">50000</span><span class="p">;</span></pre>
</div>
<p>These each represent the same query and can be transformed into a single parameterized query:</p>
<div class="highlight">
<pre><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">users</span> <span class="k">WHERE</span> <span class="n">karma</span> <span class="k">BETWEEN</span> <span class="o">?</span> <span class="k">AND</span> <span class="o">?</span><span class="p">;</span></pre>
</div>
<p>Trying to use clever tricks with quotes in order to inject arbitrary SQL code becomes futile. Parameters are considered values, and have no effect on the structure of the query itself.</p>
<p>Parameterized queries are therefore efficient and go a long way towards preventing SQL injection attacks in your applications. They have virtually no downside.</p>
<p>Newbie developers often ignore the existence of this feature and end up irritating seasoned DBAs who have to deal with the consequences of their incompetence. <a href="http://freedb2.com/2009/09/08/the-article-every-dba-should-forward-to-sql-developers/">Leon Katsnelson argues</a> that this is such an important matter, that every DBA should forward <a href="http://www.computerworld.com/s/article/9137478/Opinion_No_more_excuses_for_SQL_injection_attacks">this Computerworld article</a> to their developers. I tend to agree with how important of an issue that is.</p>
<p>That article provides the following example in Java:</p>
<div class="highlight">
<pre><span class="n">String</span> <span class="n">lastName</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getParameter</span><span class="o">(</span><span class="s">"lastName"</span><span class="o">);</span>
<span class="n">String</span> <span class="n">query</span> <span class="o">=</span> <span class="s">"select * from customers where last_name = ?"</span>
<span class="n">PreparedStatement</span> <span class="n">pstmt</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="na">prepareStatement</span><span class="o">(</span><span class="n">query</span><span class="o">);</span>
<span class="n">pstmt</span><span class="o">.</span><span class="na">setString</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">lastName</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span> <span class="n">ResultSet</span> <span class="n">results</span> <span class="o">=</span> <span class="n">pstmt</span><span class="o">.</span><span class="na">execute</span><span class="o">();</span> <span class="o">}</span></pre>
</div>
<p>Here I&#8217;ll show you an example of how to work with parameterized queries from Ruby and Python. I&#8217;ll use the Ruby and Python drivers for <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2</a>.</p>
<p>Ruby first:</p>
<div class="highlight">
<pre><span class="nb">require</span> <span class="s1">'ibm_db'</span>

<span class="n">conn</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">"mydb"</span><span class="p">,</span> <span class="s2">"db2inst1"</span><span class="p">,</span> <span class="s2">"mypassword"</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s2">"SELECT * FROM users WHERE karma BETWEEN ? AND ?"</span>
<span class="n">pstmt</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>

<span class="n">values</span> <span class="o">=</span> <span class="o">[</span><span class="mi">500</span><span class="p">,</span> <span class="mi">999</span><span class="o">]</span>
<span class="no">IBM_DB</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">pstmt</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>

<span class="k">while</span> <span class="n">row</span> <span class="o">=</span> <span class="no">IBM_DB</span><span class="o">.</span><span class="n">fetch_array</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span>
  <span class="nb">puts</span> <span class="s2">"</span><span class="si">#{</span><span class="n">row</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span><span class="si">}</span><span class="s2">:</span><span class="si">#{</span><span class="n">row</span><span class="o">[</span><span class="mi">1</span><span class="o">]</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span></pre>
</div>
<p>We load the driver (use <code>mswin32/ibm_db</code> on Windows, and <code>ibm_db.bundle</code> on Mac), create a prepared statement, and then bind the two parameter values to it through the <code>execute</code> method. We then fetch the resultset one row at a time and print the value of the first two fields for each record. For fine-tuned control we could have used the <a href="http://rubyibm.rubyforge.org/docs/driver/0.9.0/rdoc/classes/IBM_DB.html#M000005">IBM_DB::bind_param</a> method.</p>
<p>The Python version is very similar:</p>
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">ibm_db</span>

<span class="n">conn</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s">"mydb"</span><span class="p">,</span> <span class="s">"db2inst1"</span><span class="p">,</span> <span class="s">"mypassword"</span><span class="p">)</span>

<span class="n">query</span> <span class="o">=</span> <span class="s">"SELECT * FROM users WHERE karma BETWEEN ? AND ?"</span>
<span class="n">pstmt</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>

<span class="n">values</span> <span class="o">=</span> <span class="p">(</span><span class="mf">500</span><span class="p">,</span> <span class="mf">999</span><span class="p">)</span>
<span class="n">ibm_db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">pstmt</span><span class="p">,</span> <span class="n">values</span><span class="p">)</span>

<span class="nb">tuple</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">fetch_tuple</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span>
<span class="k">while</span> <span class="nb">tuple</span><span class="p">:</span>
    <span class="k">print</span> <span class="nb">tuple</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span>
    <span class="nb">tuple</span> <span class="o">=</span> <span class="n">ibm_db</span><span class="o">.</span><span class="n">fetch_tuple</span><span class="p">(</span><span class="n">pstmt</span><span class="p">)</span></pre>
</div>
<p>As you can see, working with parameterized queries is not any harder than dynamically generating SQL queries. Yet the benefits of doing so are huge.</p>
<p>Unfortunately, despite being a very sound choice to base an Object-Relational Mapper (ORM) on, ActiveRecord does not use parameterized queries. Even when it looks like you are passing parameters to a given method, these are actually used to dynamically form an SQL query. Of course you are still free to use parameterized queries in your Rails applications by employing the driver directly. But I really think this is something ActiveRecord should be built upon.</p>
<p>Luckily for Django developers, Django&#8217;s ORM uses parameterized queries, thus improving both performance and security with a single design choice. In the Python world you couldn&#8217;t get away with ignoring parameterized queries.</p>
<p>For those of you using Rails, all is not lost. <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C 9.7</a> has a killer feature known as the <a href="http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.db2.luw.wn.doc/doc/c0054005.html">Statement Concentrator</a>, which caches similar queries allowing them to use a shared access plan. It&#8217;s not as efficient as using prepared statements in your code, but it&#8217;s the best you can do when, as in the case of ActiveRecord, you can&#8217;t use parameterized queries directly. <a href="http://freedb2.com/2009/09/08/the-article-every-dba-should-forward-to-sql-developers/">Leon&#8217;s article</a> explains in greater detail how this feature actually works.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/09/improve-the-speed-and-security-of-your-sql-queries/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Enabling support for DB2 and Python/Django/SQLAlchemy on Mac OS X Snow Leopard</title>
		<link>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/</link>
		<comments>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 23:39:34 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1099</guid>
		<description><![CDATA[This is the Python version of a post I made about Ruby a few days ago. Now that Mac OS X 10.6 is out, it’s time to leave the world of 32 bit computing behind. The pre-installed Python interpreter will run in 64 bit mode by default, so you may need to pay attention when [...]]]></description>
			<content:encoded><![CDATA[<p><em>This is the Python version of </em><a href="http://antoniocangiano.com/2009/09/03/installing-the-ruby-driver-for-db2-on-mac-os-x-snow-leopard/"><em>a post I made about Ruby</em></a><em> a few days ago.</em></p>
<p>Now that Mac OS X 10.6 is out, it’s time to leave the world of 32 bit computing behind. The pre-installed Python interpreter will run in 64 bit mode by default, so you may need to pay attention when installing some C-based eggs.</p>
<p>Assuming you have <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&amp;S_TACT=ACDB201">DB2 Express-C</a> installed already, the ibm_db Python egg for DB2 can easily be installed by following these simple steps:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo -s
<span class="nv">$ </span><span class="nb">export </span><span class="nv">IBM_DB_LIB</span><span class="o">=</span>/Users/&lt;username&gt;/sqllib/lib64
<span class="nv">$ </span><span class="nb">export </span><span class="nv">IBM_DB_DIR</span><span class="o">=</span>/Users/&lt;username&gt;/sqllib
<span class="nv">$ </span><span class="nb">export </span><span class="nv">ARCHFLAGS</span><span class="o">=</span><span class="s2">"-arch x86_64"</span>
<span class="nv">$ </span>easy_install ibm_db</pre>
</div>
<p>This will install the ibm_db C driver, and the ibm_db_dbi Python module that complies to the DB-API 2.0 specification.</p>
<p>You can verify that the installation was successful my running the following:</p>
<div class="highlight">
<pre><span class="nv">$ </span>python
<span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">ibm_db</span>
<span class="o">&gt;&gt;&gt;</span></pre>
</div>
<p>Now, for the Django adapter, install Django first (if you haven&#8217;t done so already):</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install django</pre>
</div>
<p>The Django adapter can then be installed as follows:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install ibm_db_django</pre>
</div>
<p>Finally, if have installed SQLAlchemy and wish to install the DB2 adapter for it, run:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo easy_install ibm_db_sa</pre>
</div>
<p>Please let me know if you encounter any issues, I’d be glad to help you.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/09/08/enabling-support-for-db2-and-pythondjangosqlalchemy-on-mac-os-x-snow-leopard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Startup for sale on eBay (and it&#8217;s a great deal)</title>
		<link>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/</link>
		<comments>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 14:59:32 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Startup]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1092</guid>
		<description><![CDATA[One of the best programmers I know is selling a web application on eBay, that he&#8217;s been developing and running for the past three years. Given the starting price and considering what one lucky person or company will walk away with, I must say, it&#8217;s an amazing deal. I&#8217;m writing about his auction here so [...]]]></description>
			<content:encoded><![CDATA[<p>One of the best programmers I know is <a href="http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&amp;item=300343155414#ht_1769wt_1167">selling a web application on eBay</a>, that he&#8217;s been developing and running for the past three years. Given the starting price and considering what one lucky person or company will walk away with, I must say, it&#8217;s an amazing deal. I&#8217;m writing about his auction here so that I can help it get the proper exposure it deserves and because I think it&#8217;s an incredible bargain for anyone who is interested!</p>
<p align="center"><img src="http://antoniocangiano.com/wp-content/uploads/2009/08/BlogBabel1.png" alt="BlogBabel on eBay" /></p>
<p><a href="http://it.blogbabel.com">BlogBabel</a>, the aforementioned site/web app, is a blog indexing and aggregation service that began in 2006. Amongst its features are the ability to detect and show the most popular blog discussions, weekly posts, <a href="http://it.blogbabel.com/content/books/">books</a>, <a href="http://it.blogbabel.com/content/videos/">videos</a>, and even popular blog entries based on their location (through geotagging). It also features <a href="http://it.blogbabel.com/metrics/">leaderboards</a> of the most popular blogs.</p>
<p>Its codebase uses Python and Django, and consists of 27,359 physical lines of code (roughly equivalent to 6.46 person-years, according to sloccount). The R&amp;D alone makes this application worthwhile to an interested party.</p>
<p>At this stage, BlogBabel has an Italian interface (located at it.blogbabel.com) and aggregates almost 15,000 Italian blogs and 5 million posts. Changing the interface to make it an international project that&#8217;s available in several languages, or switching to English (solely), would not be challenging in the least (they used to run a Spanish version as well, for example, but decided to discontinue it so as to focus on the Italian one).</p>
<p>BlogBabel has been featured in the mainstream Italian media and has had a noticeable influence on the Italian blogosphere. One could argue that it has been the yellow pages of the Italian blogosphere. Because of this, Ludovico Magnocavallo (the site&#8217;s creator) received substantial offers to buy BlogBabel in the past, but he turned them down because he wanted to continue building this site. Now however, due to personal circumstances and lack of time/resources, he&#8217;s willing to sell this application for what may amount to far less than its true value. And here&#8217;s the real bargain, the starting price, without a reserve, is 4,999 Euros. This is of course, a ridiculously low price for the value being offered. But Ludovico believes in letting the market decide.</p>
<p>If I had the funds lying around, I would buy it myself and gear it towards the English speaking world (in conjunction with the pre-existing Italian version). It&#8217;s a prepackaged, virtually ready-made startup with a great deal of potential both in its current state and in terms of what it could grow to become.</p>
<p>To recap, the auction includes:</p>
<ul>
<li> The domain name blogbabel.com (it.blogbabel.com has a pagerank of 6);</li>
<li>The full codebase (almost 30,000 lines of code);</li>
<li>A database containing 3 years worth of data relating to the Italian blogosphere (more than 30 GB, lots of data-mining opportunities);</li>
<li>4 hours of work to help you with setting up the site on your own servers.</li>
</ul>
<p>BlogBabel has been running smoothly for three years, and is currently under-marketed. Optimizing ads, affiliates, and similar sources of revenue wouldn&#8217;t be hard at all, especially if one were to aim this site at the English speaking world.</p>
<p>Also, Ludovico has already implemented most of the code that&#8217;s necessary to allow users to have accounts (through OpenID), but since these &#8220;social features&#8221; are not fully implemented yet, they have not been deployed in production. A buyer could decide to disregard them or finish implementing them and roll out a technorati-like service. The winner of this auction could decide to implement support for Twitter, comments on social networks, sentiment analysis, etc, on their own. The possibilities are really limitless when you start with a solid engine and crawler, and already have a great deal of data at your fingertips.</p>
<p>I know Ludovico and he&#8217;s a stand-up guy. If you are interested in this great deal, you can <a href="http://cgi.ebay.it/ws/eBayISAPI.dll?ViewItem&amp;item=300343155414#ht_1769wt_1167">bid here</a>. If you have technical questions about this auction, please feel free to contact him directly through eBay.</p>
<p>UPDATE (September 8, 2009): Ludovico received an undisclosed offer for the site and a few years of maintenance work, so the auction for the site alone was suspended.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/08/31/startup-for-sale-on-ebay-a-great-deal/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The DB2 adapter now supports Django 1.1</title>
		<link>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/</link>
		<comments>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 17:27:57 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[DB2]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=1009</guid>
		<description><![CDATA[I&#8217;m glad to announce that the API team has just released version 1.0.2 of the adapter for Django. And on my birthday to boot, what a nice present. This version extends its support to the recently released Django 1.1, as well as incorporating the feedback that was received earlier on. (For installation instructions, take a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m glad to announce that the API team has <a href="http://groups.google.com/group/ibm_db/browse_frm/thread/98c2c700412688">just released</a> version 1.0.2 of the adapter for Django. And on my birthday to boot, what a nice present. This version extends its support to the recently released Django 1.1, as well as incorporating <a href="http://antoniocangiano.com/2009/06/19/db2-express-c-97-and-the-django-adapter-released/#comments">the feedback</a> that was received earlier on. <img src='http://programmingzen.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  (For installation instructions, take a look at the <a href="http://code.google.com/p/ibm-db/wiki/ibm_db_django_README">README file</a>.)</p>
<p>IBM confirms its commitment to support Python and Django, and gives Django well deserved credentials in environments where having IBM&#8217;s support counts. Django is becoming an increasingly mature web framework with the potential to do well within the Enterprise world. Having support for <a href="http://www.ibm.com/software/data/db2/express/download.html?S_CMP=ECDDWW01&#038;S_TACT=ACDB201">DB2</a> will surely help.</p>
<p>The next step will be working with the Django team to bake DB2 support directly into Django&#8217;s releases. The code for the adapter is released under a liberal OSI-compliant license that is compatible with Django&#8217;s own BSD, and the API team is more than willing to work on the development and support of the adapter should it become part of Django. We love Django and <a href="http://djangopony.com/">ponies</a>. Let&#8217;s make this happen, guys.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/08/06/the-db2-adapter-now-supports-django-1-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Serving Django Static Files through Apache</title>
		<link>http://programmingzen.com/2009/07/22/serving-django-static-files-through-apache/</link>
		<comments>http://programmingzen.com/2009/07/22/serving-django-static-files-through-apache/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 03:27:28 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Quick Tips]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=860</guid>
		<description><![CDATA[Django&#8217;s development server is capable of serving static (media) files thanks to the view django.views.static.serve. Popular web servers like Apache, Lighttpd or NGINX are much faster though, and as such should be used in production mode. Our goal is to bypass Django and let Apache (or other valid alternatives) directly serve static files like images, [...]]]></description>
			<content:encoded><![CDATA[<p>Django&#8217;s development server is capable of serving static (media) files thanks to the view <span class="n">django</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">static</span><span class="o">.</span><span class="n">serve</span>. Popular web servers like Apache, Lighttpd or NGINX are much faster though, and as such should be used in production mode. Our goal is to bypass Django and let Apache (or other valid alternatives) directly serve static files like images, videos, CSS, JavaScript files, and so on, for us.</p>
<p>Generally speaking, for performance reasons, it&#8217;s advised that you have two different webservers serving your dynamic requests and static files. In practice, for smaller sites, people often opt to simply use one webserver. In this article, I&#8217;ll discuss how to serve the static files within your Django project, through Apache.</p>
<p>The first thing we need to do is distinguish between development and production mode. We can do so by simply specifying DEBUG = True (development), or DEBUG = False (production) within our settings.py file.</p>
<p>settings.py may include (among others) the following declarations:</p>
<div class="highlight">
<pre><span class="c"># Absolute path to the project directory</span>
<span class="n">BASE_PATH</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">))</span>

<span class="c"># Main URL for the project</span>
<span class="n">BASE_URL</span> <span class="o">=</span> <span class="s">&#39;http://example.org&#39;</span>

<span class="n">DEBUG</span> <span class="o">=</span> <span class="bp">False</span>

<span class="c"># Absolute path to the directory that holds media</span>
<span class="n">MEDIA_ROOT</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">/media/&#39;</span> <span class="o">%</span> <span class="n">BASE_PATH</span>

<span class="c"># URL that handles the media served from MEDIA_ROOT</span>
<span class="n">MEDIA_URL</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">/site_media/&#39;</span> <span class="o">%</span> <span class="n">BASE_URL</span>

<span class="c"># URL prefix for admin media -- CSS, JavaScript and images.</span>
<span class="n">ADMIN_MEDIA_PREFIX</span> <span class="o">=</span> <span class="s">&quot;</span><span class="si">%s</span><span class="s">admin/&quot;</span> <span class="o">%</span> <span class="n">MEDIA_URL</span>
</pre>
</div>
<p>*PATH constants indicate paths on your filesystem (e.g., /home/myuser/projects/myproject), while *URL constants indicate the actual URL needed to reach a given page or file.</p>
<p>Notice that it&#8217;s not unusual to have a /site_media URL that corresponds to a /media folder. In the example above, I opted to separate regular media files for the project from the standard ones that ship with Django for the admin section. To do this, all we have to do is create a symbolic link as follows:</p>
<div class="highlight">
<pre>ln -s /usr/lib/python2.5/site-packages/django/contrib/admin/media /path/to/myproject/media/admin
</pre>
</div>
<p>When you&#8217;re in development mode, and DEBUG = True, you want to let Django serve your static files. This can be done by adding the following snippet (or similar) to your urls.py:</p>
<div class="highlight">
<pre><span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">:</span>
    <span class="n">urlpatterns</span> <span class="o">+=</span> <span class="n">patterns</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">,</span>
        <span class="p">(</span><span class="s">r&#39;^site_media/(?P&lt;path&gt;.*)$&#39;</span><span class="p">,</span> <span class="s">&#39;django.views.static.serve&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s">&#39;document_root&#39;</span><span class="p">:</span> <span class="n">settings</span><span class="o">.</span><span class="n">MEDIA_ROOT</span><span class="p">}),</span>
    <span class="p">)</span>
</pre>
</div>
<p>In production mode, the code contained within the if clause will not be executed as we&#8217;ve set DEBUG to False within settings.py.</p>
<p>From the Django side of things, we are good. We now need to instruct Apache. Within your virtual host file, you can specify something along the lines of:</p>
<div class="highlight">
<pre><span class="nt">&lt;VirtualHost</span> <span class="s">*:80</span><span class="nt">&gt;</span>

  <span class="c">#...</span>

  <span class="nb">SetHandler</span> python-program
  <span class="nb">PythonHandler</span> django.core.handlers.modpython
  <span class="nb">SetEnv</span> DJANGO_SETTINGS_MODULE myproject.settings
  <span class="nb">PythonDebug</span> <span class="k">On</span>
  <span class="nb">PythonAutoReload</span> <span class="k">Off</span>
  <span class="nb">PythonPath</span> <span class="s2">&quot;[&#39;/usr/lib/python2.5/site-packages/django&#39;, &#39;/path/to/myproject&#39;] + sys.path&quot;</span>

  <span class="c">#...</span>

  <span class="nb">Alias</span> <span class="sx">/site_media</span> <span class="s2">&quot;/path/to/myproject/media&quot;</span>
  <span class="nt">&lt;Location</span> <span class="s">&quot;/site_media&quot;</span><span class="nt">&gt;</span>
    <span class="nb">SetHandler</span> <span class="k">None</span>
  <span class="nt">&lt;/Location&gt;</span>
<span class="nt">&lt;/VirtualHost&gt;</span>
</pre>
</div>
<p>The first group of declarations essentially tells Apache to use mod_python to handle any incoming requests. However, we don&#8217;t want Django to deal with static files, so the second group of declarations, aliases/maps the /site_media URL with the actual media directory on the server, and tells Apache to threat it as static content (with SetHandler None) bypassing de facto Django.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/07/22/serving-django-static-files-through-apache/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Memoization in Ruby and Python</title>
		<link>http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/</link>
		<comments>http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/#comments</comments>
		<pubDate>Tue, 19 May 2009 03:59:06 +0000</pubDate>
		<dc:creator>Antonio Cangiano</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[Quick Tips]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://antoniocangiano.com/?p=771</guid>
		<description><![CDATA[Wikipedia defines memoization as &#8220;an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously-processed inputs.&#8221;. This typically means caching the returning value of a function in a dictionary of sorts using the parameters passed to the function as a key. This is done [...]]]></description>
			<content:encoded><![CDATA[<p>Wikipedia defines memoization as &#8220;an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously-processed inputs.&#8221;. This typically means caching the returning value of a function in a dictionary of sorts using the parameters passed to the function as a key. This is done in order to reuse that returning value immediately without calculating it again, when the function is invoked with the same arguments. Even though we are trading space for time, it is often invaluable for speeding up certain recursive functions and when dealing with dynamic programming where intermediate calls are often repeated many times.</p>
<p>Using memoization in Ruby is very easy thanks to the memoize gem. The first step to getting started is therefore to install it:</p>
<div class="highlight">
<pre><span class="nv">$ </span>sudo gem install memoize
Successfully installed memoize-1.2.3
1 gem installed
Installing ri documentation for memoize-1.2.3...
Installing RDoc documentation for memoize-1.2.3...
</pre>
</div>
<p>Now we can use the memoize method as illustrated in the example below:</p>
<div class="highlight">
<pre><span class="nb">require</span> <span class="s1">&#39;rubygems&#39;</span>
<span class="nb">require</span> <span class="s1">&#39;memoize&#39;</span>
<span class="nb">require</span> <span class="s1">&#39;benchmark&#39;</span>
<span class="kp">include</span> <span class="no">Memoize</span>

<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
  <span class="k">return</span> <span class="n">n</span> <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span>
  <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
<span class="k">end</span>

<span class="no">Benchmark</span><span class="o">.</span><span class="n">bm</span><span class="p">(</span><span class="mi">15</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">b</span><span class="o">|</span>
  <span class="n">b</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Regular fib:&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">fib</span><span class="p">(</span><span class="mi">35</span><span class="p">)</span> <span class="p">}</span>
  <span class="n">b</span><span class="o">.</span><span class="n">report</span><span class="p">(</span><span class="s2">&quot;Memoized fib:&quot;</span><span class="p">)</span> <span class="p">{</span> <span class="n">memoize</span><span class="p">(</span><span class="ss">:fib</span><span class="p">);</span> <span class="n">fib</span><span class="p">(</span><span class="mi">35</span><span class="p">)}</span>
<span class="k">end</span>
</pre>
</div>
<p>In the first block we simply invoke fib(35), while in the second one we first invoke the method memoize(:fib) to memoize the method fib. Running this code on my machine prints the following:</p>
<div class="highlight">
<pre>                     user     system      total        real
Regular fib:    55.230000   0.160000  55.390000 <span class="o">(</span> 55.819205<span class="o">)</span>
Memoized fib:    0.000000   0.000000   0.000000 <span class="o">(</span>  0.001305<span class="o">)</span>
</pre>
</div>
<p>We went from almost a minute of run time to an instantaneous execution. Optionally we could even pass a file location to the function memoize and this would use marshaling to dump and load the cached values on/from disk.</p>
<p>For Python we can write a simple decorator that behaves in a similar manner. In its simplest form it can be implemented as follows:</p>
<div class="highlight">
<pre><span class="c"># memoize.py</span>

<span class="k">def</span> <span class="nf">memoize</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
    <span class="n">cache</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
        <span class="k">try</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">cache</span><span class="p">[</span><span class="n">args</span><span class="p">]</span>
        <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="n">function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
            <span class="n">cache</span><span class="p">[</span><span class="n">args</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span>
            <span class="k">return</span> <span class="n">val</span>
    <span class="k">return</span> <span class="n">decorated_function</span>
</pre>
</div>
<p>Or more efficiently:</p>
<div class="highlight">
<pre><span class="c"># memoize.py</span>

<span class="k">def</span> <span class="nf">memoize</span><span class="p">(</span><span class="n">function</span><span class="p">):</span>
    <span class="n">cache</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">args</span> <span class="ow">in</span> <span class="n">cache</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">cache</span><span class="p">[</span><span class="n">args</span><span class="p">]</span>
        <span class="k">else</span><span class="p">:</span>
            <span class="n">val</span> <span class="o">=</span> <span class="n">function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
            <span class="n">cache</span><span class="p">[</span><span class="n">args</span><span class="p">]</span> <span class="o">=</span> <span class="n">val</span>
            <span class="k">return</span> <span class="n">val</span>
    <span class="k">return</span> <span class="n">decorated_function</span>
</pre>
</div>
<p>When the memoized function has been invoked, we look in the cache to see if an entry for the given arguments already exist. If it does, we immediately return that value. If not, we call the function, cache the results and return its returning value.</p>
<p>Truth be told, the limit of this approach lies in the fact that since we are using a dictionary, only immutable objects can be used as keys. For example, we can use a tuple but are not allowed to have a list as a parameter. For the example within this article, this approach will suffice, but to take advantage of memoization when using arguments that are mutable, you may want to consider the approach described in <a href="http://code.activestate.com/recipes/466320/">this recipe</a>.</p>
<p>We can now rewrite the Ruby example above in Python as follows:</p>
<div class="highlight">
<pre><span class="kn">import</span> <span class="nn">timeit</span>
<span class="kn">from</span> <span class="nn">memoize</span> <span class="kn">import</span> <span class="n">memoize</span>

<span class="k">def</span> <span class="nf">fib1</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mf">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">fib1</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib1</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">2</span><span class="p">)</span>

<span class="nd">@memoize</span>
<span class="k">def</span> <span class="nf">fib2</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mf">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">fib2</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">fib2</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mf">2</span><span class="p">)</span>	

<span class="n">t1</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="s">&quot;fib1(35)&quot;</span><span class="p">,</span> <span class="s">&quot;from __main__ import fib1&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="n">t1</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
<span class="n">t2</span> <span class="o">=</span> <span class="n">timeit</span><span class="o">.</span><span class="n">Timer</span><span class="p">(</span><span class="s">&quot;fib2(35)&quot;</span><span class="p">,</span> <span class="s">&quot;from __main__ import fib2&quot;</span><span class="p">)</span>
<span class="k">print</span> <span class="n">t2</span><span class="o">.</span><span class="n">timeit</span><span class="p">(</span><span class="mf">1</span><span class="p">)</span>
</pre>
</div>
<p>Running this code on my machine prints the following:</p>
<div class="highlight">
<pre>9.32223105431
0.000314950942993
</pre>
</div>
<p>In Python 2.5&#8242;s case by employing memoization we went from more than nine seconds of run time to an instantaneous result.</p>
<p>Granted we don&#8217;t write Fibonacci applications for a living, but the benefits and principles behind these examples still stand and can be applied to everyday programming whenever the opportunity, and above all the need, arises.</p>
]]></content:encoded>
			<wfw:commentRss>http://programmingzen.com/2009/05/18/memoization-in-ruby-and-python/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
	</channel>
</rss>
